У меня есть подкласс NSView, у которого есть свойство, которое я хочу привязать. В подклассе я реализовал следующее:
myView.h:
@property (readwrite, retain) NSArray *representedObjects;
myView.m:
@synthesize representedObjects;
+(void)initialize
{
[self exposeBinding: @"representedObjects"];
}
-(void)bind:(NSString *)binding toObject:(id)observableController withKeyPath:(NSString *)keyPath options:(NSDictionary *)options
{
if ([binding isEqualToString:@"representedObjects"]) {
[observableController addObserver: self forKeyPath:@"arrangedObjects" options:NSKeyValueChangeNewKey context:nil];
} else {
[super bind: binding toObject:observableController withKeyPath:keyPath options: options];
}
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if ([keyPath isEqualToString:@"arrangedObjects"]) {
[self setRepresentedObjects: [object arrangedObjects]];
}
}
Затем я создаю привязку к arrayController в -[AppController awakeFromNib]:
[myView bind:@"representedObjects" toObject:arrayController withKeyPath:@"arrangedObjects" options: nil];
Это правильный способ реализации привязки? Это связано с большим количеством шаблонного кода, который заставляет меня думать, что я делаю что-то не так.
Я думал, что NSObject автоматически реализует то, что я сделал вручную в -bind:toObject:withKeyPath:options:, но, похоже, это не так. Если я закомментирую свой -bind:toObject:withKeyPath:options:, метод setRepresentObjects никогда не будет вызван.
Дополнительная информация: я провел дополнительное расследование и пришел к выводу, что мой первоначальный подход верен и вам придется отказаться от -bind:toObject:withKeyPath:options:. Вот цитата из Темы программирования привязок какао: как работают привязки?:
В методе bind: toObject: withKeyPath: options: объект должен как минимум выполнять следующие действия:
- Определите, какая привязка устанавливается
- Запишите, к какому объекту он привязан, используя какой путь и с какими параметрами.
- Зарегистрируйтесь в качестве наблюдателя ключевого пути объекта, к которому он привязан, чтобы получать уведомления об изменениях.
Пример кода в листинге 2 показывает частичную реализацию метода bind: toObject: withKeyPath: options: джойстика, имеющего дело только с привязкой угла.
Листинг 2 Частичная реализация метода bind: toObject: withKeyPath: options для класса Joystick:
static void *AngleBindingContext = (void *)@"JoystickAngle"; - (void)bind:(NSString *)binding toObject:(id)observableObject withKeyPath:(NSString *)keyPath options:(NSDictionary *)options { // Observe the observableObject for changes -- note, pass binding identifier // as the context, so you get that back in observeValueForKeyPath:... // This way you can easily determine what needs to be updated. if ([binding isEqualToString:@"angle"]) { [observableObject addObserver:self forKeyPath:keyPath options:0 context:AngleBindingContext]; // Register what object and what keypath are // associated with this binding observedObjectForAngle = [observableObject retain]; observedKeyPathForAngle = [keyPath copy]; // Record the value transformer, if there is one angleValueTransformer = nil; NSString *vtName = [options objectForKey:@"NSValueTransformerName"]; if (vtName != nil) { angleValueTransformer = [NSValueTransformer valueTransformerForName:vtName]; } } // Implementation continues...
Это ясно показывает, что класс Joystick (который является подклассом NSView) должен переопределить -bind:toObject:withKeyPath:options:.
Я нахожу это удивительным. Я скептически отнесся к этому выводу, так как не нашел других примеров кода, которые бы это сделали. Однако, поскольку официальная документация Apple говорит, что я должен отказаться -bind:toObject:withKeyPath:options:, я пришел к выводу, что это правильный подход.
Я был бы очень рад, если бы кто-нибудь смог доказать, что я неправ!