Одна из вещей, в которой я всегда был неуверен, - это как правильно обрабатывать связь между пользовательским подклассом NSControl
и подклассом NSCell
. На протяжении моего знакомства с Какао я видел, как он несколько раз упоминал, как родительский элемент управления предоставляет многие из тех же методов, средств доступа и мутаторов, что и реализация дочерней ячейки / ячеек. Например, классы NSControl
и NSCell
имеют -isEnabled
и -setEnabled:
в своих файлах заголовков:
NSControl.h
- (BOOL)isEnabled;
- (void)setEnabled:(BOOL)flag;
NSCell.h
- (BOOL)isEnabled;
- (void)setEnabled:(BOOL)flag;
Я понимаю, что класс NSControl
предоставляет методы «прикрытия» для большинства свойств, найденных в NSCell
. Что меня больше интересует, так это то, как они реализованы? Или, что еще лучше, как реализовать общие свойства своих собственных подклассов? Очевидно, что только инженеры Apple действительно знают, что происходит внутри их фреймворков, но я подумал, что, может быть, кто-нибудь сможет пролить свет на лучший способ имитировать подход метода обложек Apple в красивой и понятной форме.
Я не умею объяснять, поэтому приведу пример того, о чем я говорю. Скажем, я разделил NSControl
на подклассы так:
BSDToggleSwitch.h
#import "BSDToggleSwitchCell.h"
@interface BSDToggleSwitch : NSControl
@property (nonatomic, strong) BSDToggleSwitchCell *cell;
@property (nonatomic, assign) BOOL sharedProp;
@end
И я разделил NSActionCell
на подклассы:
BSDToggleSwitchCell.h
#import "BSDToggleSwitch.h"
@interface BSDToggleSwitchCell : NSActionCell
@property (nonatomic, weak) BSDToggleSwitch *controlView;
@property (nonatomic, assign) BOOL sharedProp;
@end
Как видите, у них обоих есть общее свойство под названием sharedProp
.
У меня такой вопрос: каков стандартный способ эффективной синхронизации общего свойства между элементом управления и ячейкой? Это может показаться субъективным вопросом, и я полагаю, что это так, но я хотел бы думать, что в большинстве случаев существует «лучший способ» сделать это.
Раньше я использовал всевозможные методы, но я хотел бы сузить круг способов обработки и использовать только те методы, которые обеспечивают наилучшую целостность данных с наименьшими накладными расходами. Стоит ли использовать привязки? А как насчет реализации пользовательских мутаторов, которые вызывают метод сопоставления своих аналогов? КВО? Я безнадежный?
Вот некоторые из вещей, которые я делал в прошлом (некоторые или все из которых могут быть совершенно нелепыми или откровенно неправильными):
Привязки какао - я бы просто привязал свойство элемента управления к свойству ячейки (или наоборот):
[self bind:@"sharedProp" toObject:self.cell withKeyPath:@"sharedProp" options:nil];
Это кажется довольно хорошим подходом, но к какому объекту вы бы привязались / с какого? Я прочитал всю документацию KVO / KVC / Bindings, но я никогда особо не осознавал важность направленности привязки, когда свойство должно быть одинаковым в любом случае. Есть ли какое-то общее правило?
Отправлять сообщения от мутаторов - я бы отправил ячейке сообщение от мутатора элемента управления:
- (void)setSharedProp:(BOOL)sharedProp { if ( sharedProp == _sharedProp ) return; _sharedProp = sharedProp; [self.cell setSharedProp:sharedProp]; }
Тогда я бы сделал то же самое в реализации ячейки:
- (void)setSharedProp:(BOOL)sharedProp { if ( sharedProp == _sharedProp ) return; _sharedProp = sharedProp; [self.controlView setSharedProp:sharedProp]; }
Это тоже кажется довольно разумным, но также более подверженным ошибкам. Если один объект отправляет сообщение другому без проверки значения, бесконечный цикл может возникнуть довольно легко, верно? В приведенных выше примерах я добавил проверки по этой причине, но я уверен, что есть способ получше.
Наблюдать и сообщать - я бы заметил изменения свойств в реализации каждого объекта:
static void * const BSDPropertySyncContext = @"BSDPropertySyncContext"; - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { if ( context == BSDPropertySyncContext && [keyPath isEqualToString:@"sharedProp"] ) { BOOL newValue = [[change objectForKey:NSKeyValueChangeNewKey] boolValue]; if ( newValue != self.sharedProp ) { [self setSharedProp:newValue]; } } else { [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; } }
Еще раз, это кажется выполнимым, но мне не нравится писать оператор
if
для каждого отдельного общего свойства. Помимо наблюдений, я также отправлял уведомления, но, поскольку взаимосвязь между ячейками управления примерно такая же «один-к-одному», насколько это возможно (сладкая игра слов), это просто кажется глупым.
Опять же, я знаю, что это немного субъективно, но я бы очень признателен за некоторые рекомендации. Я уже некоторое время изучаю Cocoa / Objective-C, и это беспокоило меня с самого начала. Мне действительно может помочь знание того, как другие обрабатывают синхронизацию свойств между элементами управления и ячейками!
Спасибо!