Post

Replies

Boosts

Views

Activity

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:
2w
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:
2w
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).
2w