Помощь с наблюдением значения ключа - PullRequest
2 голосов
/ 02 октября 2009

Мне нужно немного помочь с КВО, я на полпути. Я пытаюсь вызвать метод, когда что-то в контроллере дерева меняется.

Поэтому я использую этот код для регистрации в качестве КВО.

[theObject addObserver: self
            forKeyPath: @"myKeyPath"
               options: NSKeyValueObservingOptionNew
               context: NULL];

Но как мне вызвать метод, когда ключевой путь, который я наблюдаю, меняется?

Еще один вопрос: когда я добавляю себя в качестве наблюдателя, я хочу, чтобы ключевой путь был свойством в моей модели основных данных, правильно ли я это сделал?

Ответы [ 4 ]

6 голосов
/ 02 октября 2009

Переопределить observeValueForKeyPath:ofObject:change:context: для отправки метода, который вы хотите вызвать.

@interface Foo : NSObject {
    NSDictionary *dispatch;
    ...
}
@end
@implementation Foo
-(id)init {
    if (self = [super init]) {
        dispatch = [[NSDictionary dictionaryWithObjectsAndKeys:NSStringFromSelector(@selector(somethingHappenedTo:with:)),@"myKeyPath",...,nil] retain];
        ...
    }
}
...
- (void)observeValueForKeyPath:(NSString *)keyPath
            ofObject:(id)object
            change:(NSDictionary *)change
            context:(void *)context
{
    SEL msg = NSSelectorFromString([dispatch objectForKey:keyPath]);
    if (msg) {
        [self performSelector:msg withObject:object withObject:keyPath];
    }
    [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
...

Подробнее см. " Получение уведомления об изменении ".

5 голосов
/ 02 октября 2009

Я бы порекомендовал вам взглянуть на категорию инструментов Google для Mac GTMNSObject + KeyValueObserving.h или хотя бы на блог пост Майкла Эша, который вдохновил ее. По сути, правильное ручное КВО очень тонко , а шаблон, предлагаемый API, не идеален. Гораздо лучше поместить в API другой слой (как это делает GTMNSObject + KeyValueObserving), который делает вещи более похожими на NSNotification API и скрывает некоторые источники тонких ошибок.

Используя GTMNSObject + KeyValueObserving, вы бы сделали

[theObject gtm_addObserver:self
                forKeyPath:@"myKeyPath"
                  selector:@selector(myCallbackSelector:)
                  userInfo:nil
                   options:NSKeyValueObservingOptionNew];

и ваш -myCallbackSelector: будет вызван, когда значение в @"myKeyPath" изменится с аргументом типа GTMKeyValueChangeNotification, который инкапсулирует всю необходимую информацию, которая может вам понадобиться.

Таким образом, вам не нужно иметь большую таблицу диспетчеризации в observeValueForKeyPath:ofObject:change:context (в действительности она поддерживается для вас категорией) или вам нужно беспокоиться о правильном способе использования указателя context, чтобы избежать конфликт с супер / субклассами и т. д.

4 голосов
/ 02 октября 2009

Вы должны реализовать это, и оно будет вызываться при изменении ключевого пути:

 (void)observeValueForKeyPath:(NSString *)keyPath
                     ofObject:(id)object
                       change:(NSDictionary *)change
                      context:(void *)context;

Подробнее здесь .

3 голосов
/ 13 августа 2010

(эту технику я выучил здесь: http://www.bit -101.com / blog /? P = 1999 )

Вы можете передать метод в «контексте», например

[theObject addObserver:self 
            forKeyPath:@"myKeyPath"
               options:NSKeyValueObservingOptionNew
               context:@selector(doSomething)];

.. затем в методеViewValueForKeyPath вы приводите его к типу селектора SEL, а затем выполняете его.

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    SEL selector = (SEL)context;
    [self performSelector:selector];
}

Если вы хотите передать данные в метод doSomething, вы можете использовать ключ 'new' в словаре 'change', например:

[theObject addObserver:self 
              forKeyPath:@"myKeyPath"
                 options:NSKeyValueObservingOptionNew
                 context:@selector(doSomething:)]; // note the colon

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
    {
        SEL selector = (SEL)context;

        // send the new value of observed keyPath to the method
        [self performSelector:selector withObject:[change valueForKey:@"new"]]; 
    }


-(void)doSomething:(NSString *)newString // assuming it's a string
{
      label.text = newString;
}
...