Post

Replies

Boosts

Views

Activity

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:
Feb ’26
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:
Feb ’26
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:
Feb ’26
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:
Feb ’26
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
Reply to NSURL - Are Cached Resource Values Really Automatically Removed After Each Pass Through the Run Loop?
When you access a property on the main thread, the system checks to see if the cached value is still valid, that is, has the main thread ‘turned’ between when you last got the property and now. I see. IMHO binding cache invalidation to the turning of a run loop while simultaneously recommending accessing -getResourceValue:forKey: on a background queue feels somewhat peculiar but I guess that peculiarity came during that long evolution. The main benefit of caching just until the run loop turns I guess would help if you were continuously calling -getResourceValue:forKey: in loop or in the middle of event handling but I wouldn't expect that to be so common given the recommendation to call -getResourceValue:forKey: off the main thread when possible. The downside with this short lived cache is that other threads can read stale values from -getResourceValue:forKey: calls unless they explicitly clear the cache using -removeCachedResourceValueForKey: etc. but using those methods wasn't always safe but hopefully they are now. I was working on just getting metadata I need with other APIs and caching them but there are some important resource values I need that seemingly are only available through the NSURL apis :)
Topic: App & System Services SubTopic: General Tags:
Jan ’26
Reply to NSURL - Are Cached Resource Values Really Automatically Removed After Each Pass Through the Run Loop?
So I've discovered if you create the NSURL on a background thread you can get stale resource values even on the next churn of the run loop. But whose run loop 'owns' the URL resources? The main thread's run loop ? The run loop of the thread the URL was created on? Or does NSURL do something like this: - (BOOL)getResourceValue:(out id _Nullable * _Nonnull)value forKey:(NSURLResourceKey)key error:(out NSError ** _Nullable)error API_AVAILABLE(macos(10.6), ios(4.0), watchos(2.0), tvos(9.0)); { // do whatever to get the resource value //-- // schedule delete from cache. [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(clearResourceValueForKey:) object:key]; [self performSelector:@selector(clearResourceValueForKey:) withObject:key afterDelay:0.0]; } I don't see how you can tie cached resource value state to a run loop - it doesn't make any sense to me, especially since the documentation advises doing file operations on a background thread/queue because hitting the disk can be slow. What if I'm sorting an array of NSURLs by some metadata on a background thread and the main thread run loop is just happily invalidating the cache resources behind my back? Maybe I'm not understanding something. IMO I think better behavior would be just to cache on first access and keep it until I explicitly invalidate it but I guess I have to use CFURL for that. I think it makes more sense to let the developer flush the cache in response to file coordination or whatever API being used to monitor the URL but I guess I have to build a cache on top of the cache.
Topic: App & System Services SubTopic: General Tags:
Jan ’26
Reply to NSURL - Are Cached Resource Values Really Automatically Removed After Each Pass Through the Run Loop?
Thanks for responding. I haven't yet been able to reproduce the issue in a small test project so either they made changes in a macOS update or there is some timing issue and/or way the NSURL is initialized in my real project teases the issue out. But I promise I got stale value for nonexistent NSURLIsHiddenKey until I started explicitly dumping it. In my real project the URL comes for -fileURLWithPath: (and initially created on a background thread). My real project is large and complex so when I have more time I'll have to see if I can isolate the issue in a small sample. Due the request by iOS and the server cache the user may see some discrepancies or additional nuances in how and caching behave, particularly regarding stale values. I'm on macOS. Explicit cache management is recommended, especially when dealing with URLs that may have changed state (e.g., deleted or modified), to ensure your application behaves predictably across different environments and runtime sessions. 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? I would certainly prefer explicit cache management. Chucking cached resource values at every churn of the run loop seems silly and IMO could cause unintended performance issues because the next time the app asks for the cache resource value I presume we hit the disk unnecessarily when nothing has changed. Chucking cached values at every churn of the run loop really reduces the benefits of caching in the first place - developers have to cache on top of the cache but you don't know what's cache? The only way to be sure you don't get a stale value is to call -removeCacheResourceValue methods, which again seems to reduce the benefits of NSURL caching in the first place. Also the problem with explicit cache management is I don't know if resource values are shared across NSURL instances. In the past I had a talk with an Apple badged person and I think he told me it was (or could be at that time but I'll have to check notes). At that time I discovered that calls to -removeResourceValueForKey and/or -removeAllCachedResourceValues could cause crashes. Do you know if each NSURL instance gets its own isolated cache or are they still shared by NSURLs that point to the same file (which I don't think would be safe)?
Topic: App & System Services SubTopic: General Tags:
Jan ’26
Reply to How can I be notified if another app goes full screen on macOS?
If there is a way to get notified when another app goes full screen, I'm unaware of it. If it isn't appropriate for your status windows to ever be displayed in full screen mode have you tried using NSWindowCollectionBehaviorFullScreenNone on these windows? I have a window that should display in full screen sometimes, and like you I want to be polite and initially hide it. I've been using a hack forever to do this which mostly works but it isn't exactly pretty. It involves creating a hidden window with a certain collectionBehavior like NSWindowCollectionBehaviorFullScreenNone | NSWindowCollectionBehaviorCanJoinAllSpace and basically track if the active space contains this window. If it doesn't I assume the active space contains an app with a full screen window. Again not perfect but it's the best I could think of. If there is a better way to do it, I'd also like to know.
Topic: UI Frameworks SubTopic: AppKit Tags:
Jan ’26
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:
Replies
Boosts
Views
Activity
Feb ’26
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:
Replies
Boosts
Views
Activity
Feb ’26
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:
Replies
Boosts
Views
Activity
Feb ’26
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:
Replies
Boosts
Views
Activity
Feb ’26
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).
Replies
Boosts
Views
Activity
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:
Replies
Boosts
Views
Activity
Jan ’26
Reply to NSURL - Are Cached Resource Values Really Automatically Removed After Each Pass Through the Run Loop?
When you access a property on the main thread, the system checks to see if the cached value is still valid, that is, has the main thread ‘turned’ between when you last got the property and now. I see. IMHO binding cache invalidation to the turning of a run loop while simultaneously recommending accessing -getResourceValue:forKey: on a background queue feels somewhat peculiar but I guess that peculiarity came during that long evolution. The main benefit of caching just until the run loop turns I guess would help if you were continuously calling -getResourceValue:forKey: in loop or in the middle of event handling but I wouldn't expect that to be so common given the recommendation to call -getResourceValue:forKey: off the main thread when possible. The downside with this short lived cache is that other threads can read stale values from -getResourceValue:forKey: calls unless they explicitly clear the cache using -removeCachedResourceValueForKey: etc. but using those methods wasn't always safe but hopefully they are now. I was working on just getting metadata I need with other APIs and caching them but there are some important resource values I need that seemingly are only available through the NSURL apis :)
Topic: App & System Services SubTopic: General Tags:
Replies
Boosts
Views
Activity
Jan ’26
Reply to NSURL - Are Cached Resource Values Really Automatically Removed After Each Pass Through the Run Loop?
So I've discovered if you create the NSURL on a background thread you can get stale resource values even on the next churn of the run loop. But whose run loop 'owns' the URL resources? The main thread's run loop ? The run loop of the thread the URL was created on? Or does NSURL do something like this: - (BOOL)getResourceValue:(out id _Nullable * _Nonnull)value forKey:(NSURLResourceKey)key error:(out NSError ** _Nullable)error API_AVAILABLE(macos(10.6), ios(4.0), watchos(2.0), tvos(9.0)); { // do whatever to get the resource value //-- // schedule delete from cache. [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(clearResourceValueForKey:) object:key]; [self performSelector:@selector(clearResourceValueForKey:) withObject:key afterDelay:0.0]; } I don't see how you can tie cached resource value state to a run loop - it doesn't make any sense to me, especially since the documentation advises doing file operations on a background thread/queue because hitting the disk can be slow. What if I'm sorting an array of NSURLs by some metadata on a background thread and the main thread run loop is just happily invalidating the cache resources behind my back? Maybe I'm not understanding something. IMO I think better behavior would be just to cache on first access and keep it until I explicitly invalidate it but I guess I have to use CFURL for that. I think it makes more sense to let the developer flush the cache in response to file coordination or whatever API being used to monitor the URL but I guess I have to build a cache on top of the cache.
Topic: App & System Services SubTopic: General Tags:
Replies
Boosts
Views
Activity
Jan ’26
Reply to NSURL - Are Cached Resource Values Really Automatically Removed After Each Pass Through the Run Loop?
Thanks for responding. I haven't yet been able to reproduce the issue in a small test project so either they made changes in a macOS update or there is some timing issue and/or way the NSURL is initialized in my real project teases the issue out. But I promise I got stale value for nonexistent NSURLIsHiddenKey until I started explicitly dumping it. In my real project the URL comes for -fileURLWithPath: (and initially created on a background thread). My real project is large and complex so when I have more time I'll have to see if I can isolate the issue in a small sample. Due the request by iOS and the server cache the user may see some discrepancies or additional nuances in how and caching behave, particularly regarding stale values. I'm on macOS. Explicit cache management is recommended, especially when dealing with URLs that may have changed state (e.g., deleted or modified), to ensure your application behaves predictably across different environments and runtime sessions. 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? I would certainly prefer explicit cache management. Chucking cached resource values at every churn of the run loop seems silly and IMO could cause unintended performance issues because the next time the app asks for the cache resource value I presume we hit the disk unnecessarily when nothing has changed. Chucking cached values at every churn of the run loop really reduces the benefits of caching in the first place - developers have to cache on top of the cache but you don't know what's cache? The only way to be sure you don't get a stale value is to call -removeCacheResourceValue methods, which again seems to reduce the benefits of NSURL caching in the first place. Also the problem with explicit cache management is I don't know if resource values are shared across NSURL instances. In the past I had a talk with an Apple badged person and I think he told me it was (or could be at that time but I'll have to check notes). At that time I discovered that calls to -removeResourceValueForKey and/or -removeAllCachedResourceValues could cause crashes. Do you know if each NSURL instance gets its own isolated cache or are they still shared by NSURLs that point to the same file (which I don't think would be safe)?
Topic: App & System Services SubTopic: General Tags:
Replies
Boosts
Views
Activity
Jan ’26
Reply to How can I be notified if another app goes full screen on macOS?
If there is a way to get notified when another app goes full screen, I'm unaware of it. If it isn't appropriate for your status windows to ever be displayed in full screen mode have you tried using NSWindowCollectionBehaviorFullScreenNone on these windows? I have a window that should display in full screen sometimes, and like you I want to be polite and initially hide it. I've been using a hack forever to do this which mostly works but it isn't exactly pretty. It involves creating a hidden window with a certain collectionBehavior like NSWindowCollectionBehaviorFullScreenNone | NSWindowCollectionBehaviorCanJoinAllSpace and basically track if the active space contains this window. If it doesn't I assume the active space contains an app with a full screen window. Again not perfect but it's the best I could think of. If there is a better way to do it, I'd also like to know.
Topic: UI Frameworks SubTopic: AppKit Tags:
Replies
Boosts
Views
Activity
Jan ’26