Подтвердить что ты не робот

Сбой с 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) { }
}
4b9b3361

Ответ 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