2008-12-14 3 views
6

У меня есть подкласс NSView, у которого есть свойство, которое я хочу связывать. Я реализовал следующие в подклассе:Нужно ли переопределять bind: toObject: withKeyPath: options: в подклассе 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:, метод setRepresentedObjects никогда не вызывается.

Дополнительная информация: Я провел еще несколько исследований и пришел к выводу, что мой первоначальный подход верен, и вам нужно пройти поездку -bind:toObject:withKeyPath:options:. Вот цитата из Cocoa Bindings Programming Topics: How Do Bindings Work?:

В своем безвыходном: ToObject: withKeyPath: Варианты: метод объект должен как минимум выполнить следующие действия:

  • Определите связывание создается
  • Запись, что объект привязан к использованию ключа и с помощью каких опций
  • Зарегистрировать в качестве наблюдателя путь к ключу объекта, к которому он привязан, чтобы получать уведомление об изменениях

В примере кода в листинге 2 показана частичная реализация привязки Joystick: toObject: withKeyPath: options: метод, связанный с привязкой по углу.

Листинг 2 Частичная реализация привязки: ToObject: метод опций для класса джойстиков:: withKeyPath

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:, я делаю вывод, что это правильный подход.

Я был бы очень рад, если бы кто-то мог доказать мне, что не так!

+0

Связанный вопрос с большим количеством действий, на привязках с двухсторонними обновлениями: http://stackoverflow.com/questions/1169097/can-you-manually-implement-cocoa-bindings – paulmelnikow 2011-09-12 22:41:33

ответ

1

Нет, вам не нужен этот код клея.

Что вы подразумеваете под «не похоже»? Что произойдет, если вы опустите его?

0

Вам определенно необходимо реализовать -bind:toObject:withKeyPath:options: в пользовательском представлении, если вы хотите реализовать привязки в этом представлении. Ваша реализация в myView.m довольно много.

+3

Нет, вы этого не делаете. Вам нужно только вызвать функцию exposeBinding: и реализовать KVC- и KVO-совместимые аксессоры для каждого свойства bindable. @property и @synthesize делают последнюю часть для вас. – 2009-01-08 04:29:21

1

Нет, нет необходимости переопределять bind:.

Как пишет Peter Hosey в комментарии к более раннему ответу, вы можете позвонить exposeBinding: и реализовать KVC- и KVO-совместимые аксессоры и сеттеры.

MyView.h:

@interface MyView : NSView { 
    NSArray *_representedObjects; 
} 

// IBOutlet is not required for bindings, but by adding it you can ALSO use 
// an outlet 
@property (readonly, retain) IBOutlet NSArray *representedObjects; 

@end 

MyView.m:

+ (void)initialize { 
    [self exposeBinding:@"representedObjects"]; 
} 

// Use a custom setter, because presumably, the view needs to re-draw 
- (void)setRepresentedObjects:(NSArray *)representedObjects { 
    [self willChangeValueForKey:@"representedObjects"]; 
    // Based on automatic garbage collection 
    _representedObjects = representedObjects; 
    [self didChangeValueForKey:@"representedObjects"]; 

    [self setNeedsDisplayInRect:[self visibleRect]]; 
} 

Затем вы можете установить связывание программно:

[myView bind:@"representedObjects" toObject:arrayController withKeyPath:@"arrangedObjects" options: nil]; 

Чтобы установить связывание в Интерфейс Builder, ho wever, вы должны создать пользовательскую палитру.