Post

Replies

Boosts

Views

Activity

Bindings with a threaded app.. is this crazy?
I know AppKit isn't thread safe and this may seem like an obvious thing in hindsight but I was expecting cocoa bindings controllers to dispatch updates to UI elements in the main thread. I was clearly wrong in that assumption.In thinking about this problem, I started to play around with a controller object that would do exactly that... proxy observations but notify it's observers on the main thread. I put together a POC (I'm calling it AirLock for now) and it seems to work, but it was so easy that I'm nervous that I've overlooked something obvious.The setup is simple. If a control was bound to SomeObject.someKeyPath:o In IB, create an intance of AirLock and set the represented object to SomeObjecto Change the binding of the control to AirLock.representedObject.someKeyPathThis is the code for AirLock. Is there a better way?@interface AirLock : NSObject @property (nonatomic, retain) IBOutlet id representedObject; @end@interface AirLockContext : NSObject @property (nonatomic, retain) NSObject *observer; @property (nonatomic, retain) NSString *keyPath; @property (nonatomic) void *context; @end @implementation AirLockContext @end @implementation AirLock - (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context { if ([keyPath hasPrefix:@"representedObject."]) { NSString *subPath = [keyPath substringFromIndex:@"representedObject.".length]; AirLockContext *ctx = [[AirLockContext alloc] init]; ctx.observer = observer; ctx.keyPath = keyPath; ctx.context = context; [_representedObject addObserver:self forKeyPath:subPath options:options context:(void *)CFBridgingRetain(ctx)]; } else { [super addObserver:observer forKeyPath:keyPath options:options context:context]; } } - (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath context:(void *)context { if ([keyPath hasPrefix:@"representedObject."]) { // TODO } else { [super removeObserver:observer forKeyPath:keyPath context:context]; } } - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey, id> *)change context:(void *)context { AirLockContext *ctx = (__bridge AirLockContext *)context; dispatch_async(dispatch_get_main_queue(), ^{ [ctx.observer observeValueForKeyPath:ctx.keyPath ofObject:self change:change context:ctx.context]; }); } @end
Topic: UI Frameworks SubTopic: AppKit Tags:
8
0
1.9k
Mar ’23