2016-06-05 7 views
1

Я добавил наблюдатель в коде, а затем удалить его в dealloc и viewWillDisappear, но до сих пор я получаю сообщение об ошибке сключевых наблюдателей значения по-прежнему зарегистрированы с ним, когда контроллер высвобожден

*** Нагрузочным приложением из-за для исключения исключений «NSInternalInconsistencyException», причина: «Экземпляр 0x167e5980 из класс MyController2 был освобожден, а наблюдатели ключевых значений были , которые все еще зарегистрированы с ним.

Current observation info: <NSKeyValueObservationInfo 0x16719f90> (
<NSKeyValueObservance 0x16719fb0: Observer: 0x167e5980, Key path: dataContainer.report, Options: <New: YES, Old: YES, Prior: NO> Context: 0x0, Property: 0x1677df30> 
)' 

Я создал контроллер, MyController и получить новый контроллер MyController2 от него. Теперь я добавил KVO в MyController2.

- (void)viewDidLoad { 
    [super viewDidLoad]; 
    [self addObserver:self forKeyPath:@"dataContainer.report" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil]; 
} 

Тогда в observeValueForKeyPath: -

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

    id oldC = [change objectForKey:NSKeyValueChangeOldKey]; 
    id newC = [change objectForKey:NSKeyValueChangeNewKey]; 

    if([keyPath isEqualToString:@"dataContainer.report"]) { 
     if (oldC != newC) { 
      //Remove Observer 

      [self removeObserver:self forKeyPath:@"dataContainer.report" context:nil]; 
      [self updateDataContainer]; 
      [self reportView]; 
     } 
    } 
} 

Затем я попытался удалить наблюдатель в viewWillDisappear и dealloc как: -

- (void)dealloc { 
    @try{ 
     [self removeObserver:self forKeyPath:@"dataContainer.report" context:nil]; 
    }@catch(id anException){ 
    } 
} 

-(void) viewWillDisappear:(BOOL)animated{ 
    @try{ 
     [self removeObserver:self forKeyPath:@"dataContainer.report" context:nil]; 
    }@catch(id anException){ 
    } 
    [super viewWillDisappear:animated]; 
} 

я смотрел на потерянных посты, все они говорят вам нужно удалить наблюдателя. Я попытался удалить наблюдателя у обоих из них, но все же у меня проблема.

+0

ошибка показывает, что вы добавляются наблюдателем для пути к 'dataContainer.inspectionReport', но ваш код показывает путь ключа как' dataContainer .report'. –

+0

@MidhunMP извините, что я изменил эту часть из кода и забыл переходить от ошибки. Теперь я изменил его.Пожалуйста, дайте мне знать, если вы найдете что-нибудь, почему я получаю сообщение об ошибке –

+0

Я бы предложил вести журнал везде, где вы добавляете и удаляете наблюдателей, и я уверен, вы обнаружите, что они не сбалансированы. – Rob

ответ

3

Из моего опыта лучший способ добавления и удаления наблюдателя в Иос.

Добавить наблюдатель в ViewDidLoad: -

- (void)viewDidLoad { 
    [super viewDidLoad]; 
    [self addObserver:self forKeyPath:@"dataContainer.report" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil]; 
} 

Для наблюдения наблюдателя мы должны сделать это: -

Не удалять наблюдателя в observeValueForKeyPath

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

    id oldC = [change objectForKey:NSKeyValueChangeOldKey]; 
    id newC = [change objectForKey:NSKeyValueChangeNewKey]; 

    if([keyPath isEqualToString:@"dataContainer.report"]) { 
     if (oldC != newC) { 
      [self updateDataContainer]; 
      [self reportView]; 
     } 
    } 
} 

Удалить наблюдателя В dealloc:

вызов удалить раз здесь

- (void)dealloc { 
    @try{ 
     [self removeObserver:self forKeyPath:@"dataContainer.report" context:nil]; 
    }@catch(id anException){ 
    } 
} 
2

У вас должен быть логический флаг, который вы должны установить как true при добавлении наблюдателя и установить его при удалении. Добавить наблюдателя только тогда, когда этот флаг является ложным. Также добавьте проверку в viewWillDisappear перед удалением наблюдателя. Кроме того, добавить журнал

if (self.isMovingFromParentViewController || self.isBeingDismissed) { 
     if (isReportKVOAdded) { 
      [self removeObserver:self forKeyPath:@"dataContainer.report" context:nil]; 
     } 
    } 
+0

Вы должны удалить наблюдатель, как много времени, как вы добавили, это можно предотвратить с помощью флагов – Atif

+0

да Наличие Bool для добавления и удаления наблюдателя является хорошей идеей. меня устраивает. – cmp

0

Swift 4 КВО с помощью наблюдателей ключевого ресурса работы над прошивкой 11 (и, вероятно, MacOS 10,13)

@objcMembers class Foo: NSObject { 
     dynamic var string = "bar" 
    } 

    var observation: NSKeyValueObservation! 

    func TestKVO() { 

     var foo = Foo() 

     // kvo in 2 lines of code 
     observation = foo.observe(\.string) { observed, change in 
      print(observed.string) 
     } 

     foo.string = "yo" // prints "yo" 
     foo = Foo() // works on iOS 11, crashes MacOS 10.12, not tested on MacOS 10.13, yet 
     foo.string = "oy" // does not print 
    } 

macOS 10.13 and iOS 11 Release Notes

+1

Следует отметить, что я использую эту технику, но у меня было несколько проблем с ней macOS 10.13.2/XCode 9.2. Я получал некоторую «попытку получить доступ к незанятому« я », но он уже был отменен» сбой при закрытии моего наблюдения. Добавление deinit {observ? .invalidate()} в мой класс остановило сбой - так что что-то не очищалось, как должно. – Giles

 Смежные вопросы

  • Нет связанных вопросов^_^