Новое в Key-Value-Observing; почему я не могу отслеживать значение int в моем AppDelegate?


У меня есть открытая переменная в моем Objective-C++ AppDelegate под названием stepsCompleted, поэтому я обращаюсь к ней в моем контроллере табличного представления с помощью [AppDelegate instance]->stepsCompleted.

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

[self addObserver:self forKeyPath:@"[AppDelegate instance]->stepsCompleted" options:0 context:NULL];

Однако, несмотря на то, что я постоянно меняю stepsCompleted в AppDelegate, мой метод:

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

}

Никогда не вызывается.

Что именно я делаю не так?

2 2

2 ответа:

Существуют различные проблемы с вашим кодом. Прежде всего, наблюдение за ключевыми значениями-это механизм наблюдения свойств объекта. Он не работает с экземпляром переменная. Таким образом, вы должны объявить "stepsCompleted" как свойство делегата приложения вместо переменной экземпляра:

@property (nonatomic) int stepsCompleted;

И установить его значение с помощью методов доступа к свойствам, например

[AppDelegate instance].stepsCompleted = newValue;

Далее, "[AppDelegate instance]->c" не является ключевым путем, и вы должны указать хотя бы один параметр наблюдения, например: NSKeyValueObservingOptionNew.

Чтобы наблюдать свойство "stepsCompleted" [AppDelegate instance], оно должно быть

[[AppDelegate instance] addObserver:self 
                         forKeyPath:@"stepsCompleted"
                            options:NSKeyValueObservingOptionNew
                            context:NULL];

Хотя это самый быстрый и простой способ, вам действительно не нужно объявлять @property, чтобы использовать KVO, вам просто нужно убедиться, что перед вызовом willChange и didChange для свойства правильно, и способ доступа к нему.

Например, в самом ручном случае вы можете реализовать stepsCompleted следующим образом:

@implementation SomeClass {
   int _stepsCompleted;
}

- (void)setStepsCompleted:(int)stepsCompleted;
{
    [self willChangeValueForKey:@“stepsCompleted”];
    _stepsCompleted = stepsCompleted;
    [self didChangeValueForKey:@“stepsCompleted”];
}

- (int)stepsCompleted;
{
    return _stepsCompleted;
}

@end

Затем, если вы заметили, что ключевой путь "stepsCompleted" на "someObject", вы будете вызваны, когда он изменится, предполагая, что вы когда-либо изменяли его только с помощью его сеттера, например пример через:

[self stepsCompleted:10];

Но поскольку Apple ввела свойства, вышесказанное можно сократить до точно эквивалентного:

self.stepsCompleted = 10;

Но это все еще очень много кода для сеттера и геттера, и вам не нужно писать все это, потому что Apple сделала пару крутых вещей за последние несколько лет. Один из них-это нотация @ property, которая в основном пишет приведенный выше код set / get для вас (с некоторыми дополнительными хорошими вещами). Так что теперь вы можете просто положить в свой .х файл:
@property int stepsCompleted;

И этих двух методов будет написана специально для вас. Пока вы уверены, что используете только точечную нотацию или вызываете сеттера напрямую, кво будет работать.