#ios #cocoa #key-value-observing
#iOS #какао #наблюдение за ключом-значением
Вопрос:
Я столкнулся с проблемой в своем приложении. По соображениям удобства моему делегату приложения проще наблюдать за его собственными свойствами. Однако при удалении делегата приложения в качестве наблюдателя я получаю сообщение об ошибке.
Я свел это к небольшому образцу кода и результату (показан позже).
Мой вопрос в том, когда незаконно удалять себя в качестве наблюдателя за моими собственными ключами и как типичный разработчик cocoa решил бы проблему в следующем примере:
из этого кода…
#import "AppDelegate.h"
@interface Thing : NSObject
@property (nonatomic, strong) Thing * next;
@property (nonatomic, strong) id value;
@end
@implementation Thing
@synthesize next,value;
(Thing*)thing
{
return [[Thing new] autorelease];
}
@end
@interface AppDelegate ()
@property (strong, nonatomic) Thing * thing;
@end
@implementation AppDelegate
@synthesize window = _window, thing;
- (void)dealloc
{
[super dealloc];
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
// Insert code here to initialize your application
Thing * thing2 = [Thing thing];
thing2.value = @"hello";
Thing * thing1 = [Thing thing];
thing1.next = thing2;
self.thing = thing1;
[self addObserver:self forKeyPath:@"thing.next.value" options:0 context:NULL];
[self addObserver:self forKeyPath:@"thing.next" options:0 context:NULL];
Thing * thing3 = [Thing thing];
thing3.value = @"goodbye";
self.thing.next = thing3;
}
- (void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
NSLog(@"value did change for keyPath '%@'", keyPath);
[self removeObserver:self forKeyPath:@"thing.next.value"];
[self removeObserver:self forKeyPath:@"thing.next"];
}
@end
Я получаю этот результат…
2011-11-03 13:32:02.123 TestKVO[11637:707] значение изменилось для ключевого пути ‘thing.next’
2011-11-03 13:32:02.124 TestKVO[11637:707] Не удается удалить наблюдателя <NSKeyValueObservance 0x103828250> для пути ключа «next.value» из <Thing 0x10381d970>, скорее всего, потому, что значение для ключа «next» изменилось без отправки соответствующего уведомления KVO. Проверьте соответствие KVO классу Thing.
Ответ №1:
Я думаю, проблема заключается в том, что вы регистрируетесь для двух источников уведомлений, которые являются включительными.
Вместо этого вы должны:
- Регистрируйтесь только для
@"thing.next"
- Внутри метода обработки уведомлений отмените регистрацию для
@"thing.next.value"
старого@"thing.next"
значения (найденного вchange
словаре), затем зарегистрируйтесь для@"thing.next.value"
нового@"thing.next"
значения (также найденного вchange
словаре).
Таким образом, привязки остаются неизменными при @"thing.next"
изменении пути к ключу.
Комментарии:
1. Это, скорее всего, правильно. когда вы регистрируетесь
thing.next.value
, ваше приложение сохраняет слабую ссылку (т. Е. Не Сохраняется) наthing.next
. Затем вы меняетеthing.next
так, что KVO запутывается, потомуthing.next
что изменилось, таким образом, изменилосьthing.next.value
, но уведомление о KVO не было отправлено дляthing.next.value
изменения. Тьфу. это может сбить с толку.
Ответ №2:
Пара вещей:
1) вы внедряете свои собственные сеттеры? если это так, вам нужно убедиться, что они соответствуют KVO, отправив willChangeValueForKey:
и didChangeValueForKey:
соответствующим образом. Найдите раздел о соответствии KVO в руководстве Apple по программированию с соблюдением ключевых значений.
РЕДАКТИРОВАТЬ: Вышесказанное было предназначено для проверки общего соответствия вашего класса. @sam правильно, что вам не нужны willChange...
и didChange...
в пользовательских установщиках, если вы не отключили автоматические уведомления.
2) вместо того, чтобы ваш объект наблюдал за его собственными свойствами (немного странно, ИМХО), вы могли бы реализовать пользовательские настройки, которые делают все, что вы хотите, в объекте при изменении значения.
Комментарии:
1. Я согласен с тем, что переопределение установщиков, вероятно, является лучшим маршрутом, но ему не нужно вызывать
willChangeValueForKey:
/didChangeValueForKey:
. На самом деле, если бы он это сделал, его методы, вероятно, сработали бы дважды, потому что kvo работает автоматически, если вы его не отключите, даже если вы пишете свои собственные настройки. См . Соответствие требованиям KVO иautomaticallyNotifiesObserversForKey:
.2. @sam прав в отношении автоматического KVO. Я имел в виду свой комментарий для проверки соответствия класса. Я отредактирую свой ответ.