Post

Replies

Boosts

Views

Activity

Reply to NSFileManager getRelationship:ofDirectoryAtURL:toItemAtURL:error: returning NSURLRelationshipSame for Different Directories
It means apps don't need to actively track the current location of their files, but can instead determine its current location whenever the user actually asks for it. What should happen if you expand a directory with four subfolders in a NSBrowser (so four columns). And the third folder moves? If an app just follows the file reference URL the UI is broken. I mean if there are/were APIs that handled this in file reference world I'm with you! The concept of file location matters to users and to a lot of apps. I hope Apple doesn't want to put apps in single file jail. Here you get that one txt document and if it moves don't worry we got you. There are other types of apps that do other things. Please don't turn macOS into iOS :)
Topic: App & System Services SubTopic: Core OS Tags:
1w
Reply to NSFileManager getRelationship:ofDirectoryAtURL:toItemAtURL:error: returning NSURLRelationshipSame for Different Directories
I'm not sure what you mean here. If you want to know the current path location, then you ask the kernel to convert the reference to a path. [..] I'm not quite sure what you're thinking of here. If you're trying to display the contents of a directory hierarchy, then the process is exactly the same for paths and references. You start with the container and recursively iterate its contents, displaying whatever you find. What about changes? FSEventStreamRef reports changes on a directory. Does it work on file reference urls? I never even thought of trying. I can pick up changes on a subfolder 4 folders away from the root folder I'm watching, all using a single FSEventStreamRef. I'm not saying it isn't possible I just don't know? how can I parse a single change using current APIs in a deep tree with opaque file reference urls that don't have a concept of location without first converting to path to see what level I'm at? Sure. Why not? That's what the Carbon File Manager did. Well I'm not totally against the idea nor was I arguing that it was impossible. I'm just saying it isn't in the API today, so I need a path to create a file. As you already mentioned previously macOS is very path based. In my original sample the code does not indicate in any obvious way that I wanted to use a file reference URL but merely asking NSFileManager the 'relationship' caused a really undesirable side effect. but I suspect this is actually a new bug, possibly introduced in Swift Foundation[1] [1] Much of the Objective C "version" of Foundation is actually written in Swift now. Lord have mercy! I have another issue that may or may not be related to this in some way but I think I'm going to have to spin up a separate thread.
Topic: App & System Services SubTopic: Core OS Tags:
1w
Reply to macOS Tahoe 26.3 - System Is Playing NSBeep At Inappropriate Times When Text Editing Ends Via -cancelOperation: (field editor)
I did programmatically change first responder via a call to -makeFirstResponder inside my responder's -cancelOperation: I've been doing this for years no issue until Tahoe 26.3. I had a reason for doing this (to end editing). I think it was to workaround some kind of bug. Now it appears that the cancelOperation 'event' wraps back to the window and NSWindow just beeps. In the case of view that uses NSBrowser I tried changing the -makeFirstResponder: call and passed in the browser itself instead of nil but I still get a beep. It still wraps the event back to the window but that key event I think should not be in the event queue anymore. In another view that uses a table view this causes a bunch of key events to get stuck in the queue and they get sent to the window later and I get a beep beep beep. In the non-browser case just passing in that table view to makeFirstResponder: seems to fix it. IN the view that uses the browser I seem to get that beep no matter what. Just overriding -cancelOperation in NSWindow subclass and not calling super is my workaround for now.
Topic: UI Frameworks SubTopic: AppKit Tags:
1w
Reply to NSFileManager getRelationship:ofDirectoryAtURL:toItemAtURL:error: returning NSURLRelationshipSame for Different Directories
Very interesting info! I can understand that thinking, but it's not the system’s perspective. The system’s "view" here is that the file reference is considered more "authoritative" than the path. I actually don't have a strong opinion about file reference urls vs. file path urls but from my perspective in the sample it is clear after the second call to createDirectoryAtURL:..., when that method returns, the fileReferenceURL left lingering in that untitleFour instance is pointing to to the wrong folder based on the fact that I fed that URL directly into a method to create a folder, the operation succeeded, yet there is still a chance to accidentally access a completely different folder through that very same instance going through the cached fileReferenceURL. MacOS itself is heavily still reliant on path, but fileReferenceURLs are the closest construct we have to an API that doesn't fall into this "trap". Yea. You can't even create a file without a path so there is that. File reference urls are great at certain things (put this file on the pasteboard - it'll work even if it moves) but you'd really need to introduce a slew of new APIs for developers to really be able to go 'pathless.' Would every method to create a file or folder have to take a parent (fileReferenceURL) parameter? There is a whole class of applications that display / organize files based on their file system location and file reference don't work very well with that concept. How does something like NSPathControl work in a world where there is no file paths? I guess that's the point. File reference urls describe what, but what about where? You might be able to organize a list of files in a tree and manage parent-child relationships using mostly file reference urls (NSURLParentDirectoryURLKey?) but I won't be the guy trying that in 2026!
Topic: App & System Services SubTopic: Core OS Tags:
2w
Reply to NSFileManager getRelationship:ofDirectoryAtURL:toItemAtURL:error: returning NSURLRelationshipSame for Different Directories
Very interesting. Thanks a lot for the detailed responses. As I mentioned briefly in a previous post I stumbled across this commenting out some things to test out an error handling code path. As a result of the matching NSURLFileResourceIdentifierKey the wrong error message was logged. In my app's case this is basically a harmless bug because I do nothing but the behavior did spark my curiousity. In any case I will most likely be removing -getRelationship: calls from app entirely soon. I'm surprised that a fileReferenceURL would be cached in a filePathURL at all. My expectation is when calling fileReferenceURL on a file path url is to get a reference to the file at the exact file path right now if it is there (or nil) and I would have to hold the fileReferenceURL on first access to follow the file around. If caching the fileReferenceURL in the URL itself has been determined to be necessary I'm also somewhat surprised an existing fileReferenceURL isn't cleared/updated when files are manipulated via high level APIs like NSFileManager -createDirectoryAtURL:.... etc. After recreation as you mentioned if you did untitledFour.fileReferenceURL you'd be manipulating the folder in trash not the new folder you created. Based on your previous reply it sounds like it would be chalked up as an app bug since you recommend grabbing the fileReferenceURL early. But IMO it isn't obviously clear by the public interface that NSURL may return a 'cached/stale' file reference url. I'm not actually doing this and i'm glad i'm aware of this possibility. It doesn't seem so far fetched that this could be a source of a dataloss bug or something worse. In my silly example it is obvious that I'm recycling the untitledFour NSURL instance. In a real complex app where you are passing NSURLs around like hot potatoes to various objects it may not be so obvious.
Topic: App & System Services SubTopic: Core OS Tags:
2w
Reply to NSFileManager getRelationship:ofDirectoryAtURL:toItemAtURL:error: returning NSURLRelationshipSame for Different Directories
The run loop itself doesn't actually "turn" at a predictable rate. Depending on how your app is architected and the overall app state, it's entirely possible for an app to go seconds or even minutes without the main thread ever running. Doesn't appear to be what's going on in this case. I made this dumb little test which can easily reproduce the issue (sorry can't get code to format well on these forums). +(MachoManURLTester*)sharedTester { static MachoManURLTester *sharedTester = nil; static dispatch_once_t token; dispatch_once(&token,^{ sharedTester = [[self alloc]init]; }); return sharedTester; } -(void)startURLTrashDance { NSAssert(NSThread.currentThread.isMainThread, @"Main thread only."); NSFileManager *fm = [NSFileManager defaultManager]; NSURL *wrapperDir = [[NSURL fileURLWithPath:NSTemporaryDirectory() isDirectory:YES] URLByAppendingPathComponent:NSUUID.UUID.UUIDString isDirectory:YES]; if (![fm createDirectoryAtURL:wrapperDir withIntermediateDirectories:YES attributes:nil error:nil]) { NSLog(@"Test failed"); return; } //[[NSWorkspace sharedWorkspace] activateFileViewerSelectingURLs:@[wrapperDir]]; NSURL *untitledFour = [wrapperDir URLByAppendingPathComponent:@"Untitled 4" isDirectory:YES]; if (![fm createDirectoryAtURL:untitledFour withIntermediateDirectories:YES attributes:nil error:nil]) { NSLog(@"Test failed"); return; } NSLog(@"Created untitled 4."); NSURL *resultingURL = nil; if (![fm trashItemAtURL:untitledFour resultingItemURL:&resultingURL error:nil]) { NSLog(@"trash failed"); return; } NSLog(@"Moved Untitled 4 to the trash."); [self performSelector:@selector(replaceTrashedURL:) withObject:untitledFour afterDelay:1.0]; [self performSelector:@selector(compareBothURLS:) withObject:@[untitledFour,resultingURL] afterDelay:4.0]; } -(void)replaceTrashedURL:(NSURL*)originalURL { NSFileManager *fm = [NSFileManager defaultManager]; if ([fm createDirectoryAtURL:originalURL withIntermediateDirectories:YES attributes:nil error:nil]) { NSLog(@"Recreated Untitled 4"); } } -(void)compareBothURLS:(NSArray<NSURL*>*)twoURLsArray { NSLog(@"4 seconds is up - let's check"); NSFileManager *fm = [NSFileManager defaultManager]; NSURL *untitledFour = twoURLsArray.firstObject; NSURL *resultingURL = twoURLsArray.lastObject; // Uncomment these fixes the relationship check: //[untitledFour removeCachedResourceValueForKey:NSURLFileResourceIdentifierKey]; //[resultingURL removeCachedResourceValueForKey:NSURLFileResourceIdentifierKey]; NSURLRelationship relationship; NSError *error = nil; if ([fm getRelationship:&relationship ofDirectoryAtURL:untitledFour toItemAtURL:resultingURL error:&error]) { if (relationship == NSURLRelationshipSame) { NSLog(@"NSURLRelationshipSame: %@ - %@?",untitledFour,resultingURL); } else if (relationship == NSURLRelationshipContains) { NSLog(@"NSURLRelationshipContains"); } else if (relationship == NSURLRelationshipOther) { NSLog(@"NSURLRelationshipOther"); } else { NSLog(@"Unknown"); } } else { NSLog(@"Error reading relationship: %@",error); } } @end Just use that class and do this in a test program. MachoManURLTester *URLTester = [MachoManURLTester sharedTester]; [URLTester startURLTrashDance]; And to answer your earlier question, YES the file reference urls do collide.
Topic: App & System Services SubTopic: Core OS Tags:
2w
Reply to NSFileManager getRelationship:ofDirectoryAtURL:toItemAtURL:error: returning NSURLRelationshipSame for Different Directories
ACTUALLY doing #2 for every call is a terrible idea for both performance and coherence issues, but that means we're basically stuck trying to sort out when to reset, not if we're going to cache. I agree. IMO the problem is not that NSURL is caching the problem is the way it caches. The way it caches forces me to cache on top of it. The documentation claims it only caches for 1 run loop turn but as previously mentioned that is not always the case and certain values tend to get 'stuck.' Building a cache on top of NSURL resource values which may or may not be stale can cause all sorts of weird behavior if you don't call -removeCacheResourceValues so I can cache on the true value...but NSURL I assume makes its cache thread safe so -removeCacheResourceValues probably isn't so cheap. Doesn't that mean the url cache is costing me performance by requiring me to clear it to get to the true values I really want to cache? Huh. That's really weird. How did you construct those URLs? Originally the URL came through NSFIlemanager enumeration, or maybe -createDirectoryAtURL: I can't remember. I'll have to try it out later when I have a little bit more time. But I just stumbled across some really weird behavior when passing a file type from Finder to my app. It could be unrelated but I wouldn't be completely surprised if it was related to this topic. I might file a bug on that later. It would be great if this forum supported private messages I'm not sure if I'm ready to provide more details yet in the open
Topic: App & System Services SubTopic: Core OS Tags:
2w
Reply to Creating a Temporary Directory with NSFileManager - NSItemReplacementDirectory creates folder in user-facing location?
The API I'm using to write the file (to the temp location) writes the file atomically and will overwrite an existing file but in the final destination I'm working in it is a user facing folder and I don't want to just assume a save location and potentially overwrite the user's data. So what I do is simply write in the temporary location atomically, then attempt to move the file in the final destination with a preferred filename without looking before I leap and if I fail to move because the file already exists, I try again with a different name. I could continue to write to the temporary location the old way but that definitely will be slower for external volumes because I do the "move" (copy/delete) across volumes. But I don't want to flash temporary folders in the Finder either. In my very limited testing it seems if I clean up the temp directory right after I finish they don't appear in Finder but I assume they will if the operation takes a long time.
Topic: App & System Services SubTopic: General Tags:
3w
Reply to NSFileManager getRelationship:ofDirectoryAtURL:toItemAtURL:error: returning NSURLRelationshipSame for Different Directories
Thanks for the reply! I actually stumbled across this while reworking things in my app to account for NSURL caching behavior I mentioned in the other thread. What I was doing not too long ago was using an NSCache on top of NSURL for resource values. At some point when responding to metadata changes I was calling -removeCacheResourceValues on a background thread to get refreshed data and I had discovered that -removeCacheResources could crash if another thread was reading at the same time. I guess at some point in my frustration I just moved some stuff around to stop the crashes (and I did). I had either forgotten or just never realized that NSURL caches only for a run loop turn (or maybe just sometimes? More on that in a second). I guess this is cool in the middle of a dragging session but apparently at some point I must've just assumed that NSURL must be caching for a more meaningful period of time (from the perspective of my app anyway) because if I didn't call -removeCachedResources I'd get stale values sometimes. SO why cache on top of a cache? And I chucked my NSCache which I never really loved but apparently that was a mistake. My bad. I guess my wish would be for NSURL to either cache forever until explicitly clear values or don't cache at all because if we're caching on a cache that may not be a cache but sometimes it seems like a cache it's hard to cache. Maybe I'm just being selfish though. But back to the collision. So I'm reworking all this (not using NSCache this time). Now as I'm rewriting my caching code I commented out few things here and there checking some error handling code paths that seem extremely unlikely to really occur and I stumble across this collision but there are many run loop turns in between these events so I don't understanding why the cached values are living for so long in this particular case. Maybe something like cancelPreviousPerformRequestsWithTarget causes cached values to live longer but I'm not suppose to worry about the implementation details. I can easily reproduce this with NSFileManager using the following steps: -trashItemURL:resultingItemURL: - grab the resultingItemURL. Put an empty new folder in the exact same location you just trashed. Compare the NSURLFileResourceIdentifierKey of the URLs you got from resultingItemURL with new folder at its old location and they match - until you programmatically remove the cached value.
Topic: App & System Services SubTopic: Core OS Tags:
3w
Reply to Appkit without storyboards XCode 26.2
@hieronim-bosch AppKit is my favorite framework, nothing else comes close. Until proven otherwise there is still no better way to make a Mac app IMHO. That said I never got into Storyboards on Mac. In Xcode 26.2 I can still create an AppKit project the "old way" which is New Project -> macOS -> App then change Interface to XIB then you get a project without a storyboard. If you want to go completely without Interface Builder you can but I don't think Apple ever had a template for that setup (well if they did I never noticed or it must have been a really long time ago). You can set the NSApplication delegate in main. #import <Cocoa/Cocoa.h> @interface AppDelegate : NSObject <NSApplicationDelegate> @property (strong) NSWindowController *mainWindowController; @end @implementation AppDelegate -(void)applicationDidFinishLaunching:(NSNotification*)aNotification { NSLog(@"Hello world!"); NSWindow *firstWindow = [[NSWindow alloc]initWithContentRect:NSMakeRect(50.0, 50.0, 400.0, 400.0) styleMask:NSWindowStyleMaskTitled backing:NSBackingStoreBuffered defer:NO]; firstWindow.title = @"Xibless"; self.mainWindowController = [[NSWindowController alloc]initWithWindow:firstWindow]; [self.mainWindowController showWindow:nil]; } @end // main.m int main(int argc, const char * argv[]) { @autoreleasepool { NSApplication *app = [NSApplication sharedApplication]; AppDelegate *appDelegate = [[AppDelegate alloc]init]; app.delegate = appDelegate; [app setActivationPolicy:NSApplicationActivationPolicyRegular]; [app run]; } } and I think you also need to build the menu bar programmatically. IMO there really is no reason to do all this. If you want to avoid Interface Builder I think it's more reasonable to just do the following: Create an Xib project. Keep the MainMenu.xib but inside it delete the window but leave the menu bar. Then in your AppDelegate just make your NSWindowController / NSWIndow in code. Then you're mostly without IB - enough for learning. Or if you want you can build the menu bar (see mainMenu property on NSApplication: https://developer.apple.com/documentation/appkit/nsapplication/mainmenu?language=objc).
Jan ’26
Reply to NSURL - Are Cached Resource Values Really Automatically Removed After Each Pass Through the Run Loop?
Also CFURL is documented to have different behavior but CFURL and NSURL aren't they 'toll free bridged' so how does that work if you cast a CFURL to a NSURL? So I just did a dumb little test to answer this. I created a CFURLRef and read kCFURLIsHiddenKey and got false (as expected) so it would cache it. Then on another CFURL instance (that points to the same file) I did the same thing (so it was cache the value). After that I set hidden to YES: NSURL *toNSURL = (__bridge NSURL * _Nonnull)cfURL; [toNSURL setResourceValue:@(YES) forKey:NSURLIsHiddenKey error:nil]; Then back to the other instance I cast that one to another NSURL: NSURL *nsCastCopiedVersion = (__bridge NSURL * _Nonnull)aCopiedCFURL; And read isHidden and it is NO. Read aCopiedCFURL hidden and it is also NO. Then dispatch after dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [URLPrinter printCF:aCopiedCFURL]; [URLPrinter printNS:nsCastCopiedVersion]; }); And got: Print copied CF Not hidden // cached value - real value is true. Print copied NSCF: Hidden // hidden true value So indeed using CFURL instead would seem to avoid this. Learn something new every day. Now if I didn't already have a million lines of code already using NSURL I would just use CF instead (still might) because at least for my app I find dumping cache values at every run loop churn undesirable. I did have a better caching system implemented at some point but seems some of it got dumped it when I implemented a workaround to avoid -removeCacheResourceValue: crashes a couple of years ago. It'll all be back in biz soon. Thanks for the help guys.
Topic: App & System Services SubTopic: General Tags:
Jan ’26