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
Post
Replies
Boosts
Views
Activity
I'm using AVAudioEngine for some very simple mixing application but I'd like to be able to use arbitrary audio devices for input (like USB devices) and not just the system selected device. Is there any simple way to do this?Ideally I'd like to be able to mix multiple hardware sources at the same time but I'd be happy at this point to just be able to change the device behind the one AVAudioInputNode instance.Thanks for any suggestions..