Posts

Post not yet marked as solved
0 Replies
1.8k Views
So I'm working on an instrument that has close to 100 parameters, and following the patterns in the examples I could find got quickly unwieldy. Wondering why one could not simply bind to key paths in the parameterTree, I eventually went down an unpleasant rabbit hole in finding out these KVO notifications do not come back in the application's preferred thread.Any way we go, this seems a really un-idiomatic way to write UI code in Cocoa.So.. I came up with this for my controller, which I don't like for several reasons, although I like it much more than dealing with outlets and actions for every control in the view.Am I doing something unnecessarily the hard way?Also, I'd think two things in XCode/AudioToolkit would be extremely valuable: 1) The ability to define a parameterTree as part of your xib/storyboard like you can with CoreData schemas, and 2) some sort of official object controller class provided which does this bridging.@synthesize parameters = _parameters; @synthesize parameterTree = _parameterTree; - (void)dealloc { if (observer != nil) { [_parameterTree removeParameterObserver:observer]; observer = nil; } } - (p2fmAudioUnit *)getAudioUnit { return _audioUnit; } - (void)setAudioUnit:(p2fmAudioUnit *)audioUnit { _audioUnit = audioUnit; dispatch_async(dispatch_get_main_queue(), ^{ if ([self isViewLoaded]) { [self connectView]; } }); } - (void) viewDidLoad { [super viewDidLoad]; self.preferredContentSize = self.view.frame.size; if (_audioUnit) { [self connectView]; } } - (void)connectView { AUParameterTree *tree = _audioUnit.parameterTree; if (tree == nil) { return; } self.parameterTree = tree; [self refresh]; [_audioUnit addObserver:self forKeyPath:@"allParameterValues" options:NSKeyValueObservingOptionNew context:NULL]; __weak AudioUnitViewController *weakSelf = self; observer = [_parameterTree tokenByAddingParameterObserver:^(AUParameterAddress address, AUValue value) { __strong AudioUnitViewController *strongSelf = weakSelf; AUParameter *param = [strongSelf->_parameterTree parameterWithAddress:address]; if (param != nil) { dispatch_async(dispatch_get_main_queue() , ^{ [strongSelf refreshParam:param]; }); } }]; } - (void)refresh { for (AUParameter *param in [_parameterTree allParameters]) { [self refreshParam:param]; } } - (void)refreshParam:(AUParameter *)param { NSArray *keys = [[param keyPath] componentsSeparatedByString:@"."]; NSUInteger len = [keys count]; if (len < 1) { return; } NSMutableDictionary *dict = _parameters; if (dict == nil) { self.parameters = [[NSMutableDictionary alloc] init]; dict = _parameters; } for (NSUInteger i = 0; i < (len-1); i++) { NSString *key = [keys objectAtIndex:i]; NSMutableDictionary *node = [dict objectForKey:key]; if (node == nil) { node = [[NSMutableDictionary alloc] init]; [dict setValue:node forKey:key]; } dict = node; } NSString *key = [keys lastObject]; BOOL addObserver = NO; if ([dict objectForKey:key] == nil) { addObserver = YES; } [dict setValue:@(param.value) forKey:key]; if (addObserver) { [dict addObserver:self forKeyPath:key options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:(void *)param]; } } - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<nskeyvaluechangekey,id> *)change context:(void *)context { if (object == _audioUnit && [keyPath isEqualToString:@"allParameterValues"]) { dispatch_async(dispatch_get_main_queue() , ^{ [self refresh]; }); } else if (context != NULL) { id p = (__bridge id)context; if ([p isKindOfClass:[AUParameter class]]) { AUParameter *param = p; AUValue new = [[change valueForKey:NSKeyValueChangeNewKey] floatValue]; AUValue old = [[change valueForKey:NSKeyValueChangeOldKey] floatValue]; if (new != old) { [param setValue:new originator:observer]; } } } }
Posted Last updated
.
Post not yet marked as solved
1 Replies
1.3k Views
This should be a pretty basic question:I have in my view controller an NSMuteableDictionary with various controls bound to key paths, like "dict.key" from the controller where "dict" is a property of the controller.This all works as one would expect unless the dictionary is updated by other means, in which case the controls do not reflect the updated values until they gain focus. The other way works fine - if the UI updates a value, I can observe the key change as one would expect.This would indicate the value is being updated outside of KVC, but I'm using [dict setValue: forKey:], so that can't be it.If I need my UI to reflect state from external modifications, is this not the correct mechanism to use? Or am I missing something really fundamental?
Posted Last updated
.
Post not yet marked as solved
1 Replies
952 Views
I have a project with three targets:- app- extension- frameworkBoth the app and extension name the framework as a dependency and as a "linked framworks and libraries".I cannot get either the app or extension to be able to #import any public header using <framework/header.h>. The necessary headers in the framework are marked public and included in the header phase.I'm not exactly new to any of this, but it's been about 10 years since I've last dealt with MacOS/XCode, so some things have obviously changed since, but this shouldn't be that fscking hard to figure out.. I've read the support articles (that are not maintained and referring to ancient versions of XCode) and there's nothing surprising or new to me in those.What basic things did I miss?
Posted Last updated
.