Сбой с removeObserver: forKeyPath: in Foundation
У меня возникли проблемы со следующими журналами сбоев, извлеченными из раздела "Сбой" в Xcode. Этот отчет о сбое затронут только несколько устройств.
Я проанализировал проблему, но я предполагаю, что это ошибка в структуре Apple. Но я не могу найти способ воспроизвести его.
Здесь аналогичное обсуждение: Помощь при сбое в removeObserver: forKeyPath:.
Любые подсказки?
Thread 0 имя: Thread 0 Crashed:
0 Фонд
0x23507591 _NSKeyValueReplaceObservationInfoForObject + 69 (NSKeyValueObserving.m: 1166)
1 Фонд
0x23506fe7 - [NSObject (NSKeyValueObserverRegistration) _removeObserver: forProperty:] + 327 (NSKeyValueObserving.m: 1552)
2 Фонд
0x23506b03 - [NSObject (NSKeyValueObserverRegistration) removeObserver: forKeyPath:] + 163 (NSKeyValueObserving.m: 1696)
3 Фонд
0x235069a7 - [NSObject (NSKeyValueObserverRegistration) removeObserver: forKeyPath: context:] + 219 (NSKeyValueObserving.m: 1663)
4 ApplicationName 0x0002e233 - [Супервизор removeObjectObserver: forKeyPath:] + 115 (Supervisor.m: 344)
где removeObjectObserver:forKeyPath:
есть
- (void) removeObjectObserver:(id)object forKeyPath:(NSString *)keyPath {
@try {
[object removeObserver:self forKeyPath:keyPath context:PrivateKVOContext];
} @catch (NSException *exception) { }
}
Ответы
Ответ 1
Observers
в Objective-C
следует использовать с дополнительным вниманием: не добавляйте одно и то же время наблюдателя к одному и тому же свойству объекта и оберните удаление, если оно есть:
if ([self observationInfo]) {
@try {
[self removeObserver:self forKeyPath:keyPath];
}
@catch (NSException *exception) {}
}
У вас возникают сбои, потому что вы пытаетесь удалить дважды наблюдателя, или вы удаляете несуществующего наблюдателя.
Вы должны добавить Observers
следующим образом:
[yourObject addObserver:self forKeyPath:keypath options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionInitial context:nil/yourContext];
EDIT:
Вы можете удалить наблюдателя на уже освобожденном объекте, что приведет к этому сбою.
if (object && [self observationInfo]) {
@try {
[self removeObserver:self forKeyPath:keyPath];
}
@catch (NSException *exception) {}
}
Ответ 2
Обычно у вас есть ivar, чтобы быть в курсе, хотите ли вы на данный момент наблюдать за ключевыми словами, или нет. Подобно @property (...) BOOL textFieldTextObserving;
И ваши методы добавления/удаления-наблюдения должны проверять это свойство перед добавлением/удалением, чтобы избежать добавления/удаления наблюдателя дважды.
Вы также можете использовать NSDictionary, если есть много объектов наблюдения и ключевых путей (чтобы сохранить @(BOOL) как объекты и-идентификаторы в качестве ключей).
В любом случае, делать вещи, используя @try-exception, не рекомендуется Objective-C.
Apple docs говорит:
"You should not use a try-catch block in place of standard programming checks for Objective-C methods. In the case of an NSArray, for example, you should always check the array’s count to determine the number of items before trying to access an object at a given index. The objectAtIndex: method throws an exception if you make an out-of-bounds request so that you can find the bug in your code early in the development cycle—you should avoid throwing exceptions in an app that you ship to users."
https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/ErrorHandling/ErrorHandling.html