Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iOS KVO - Cannot remove an observer

I have a simple Viewcontroller that is KVO compliant and has the following in it:

  - (void) viewDidAppear:(BOOL)animated
    {
        [super viewDidAppear:animated];



        [self addObserver:self forKeyPath:@"importStuff" options:0 context:NULL];
        [self addObserver:self forKeyPath:@"importStuffFailed" options:0 context:NULL];
        }

    - (void) viewWillDisappear:(BOOL)animated
    {
        [super viewWillDisappear:animated];

        [self removeObserver:self forKeyPath:@"importStuff"];
        [self removeObserver:self forKeyPath:@"importStuffFailed"];
      }

the issue im having is that sometimes user are reporting the following error:

Cannot remove an observer <MyViewController 0x145d0c8d0> for the key path "importStuff" from <MyViewController 0x1741b2280> because it is not registered as an observer.

the addObserver call is not called anywhere else in code. is it something about the life cycles im missing ? isn't viewDidAppear guaranteed to be called once (so it should register the keys right ?)

like image 290
j2emanue Avatar asked Jul 29 '15 18:07

j2emanue


2 Answers

Apple Docs say there is a way to add observer when view is visible only. According to Figure 1 - Valid State Transitions you can use pair viewWillAppear/viewWillDisppear for adding and removing observers. At the same time you can use init/dealloc pair, but not viewDidLoad/dealloc - view can be not loaded, but controller deallocated.

Your code should be:

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];

    [self addObserver:self forKeyPath:@"importStuff" options:0 context:NULL];
    [self addObserver:self forKeyPath:@"importStuffFailed" options:0 context:NULL];
}

- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];

    [self removeObserver:self forKeyPath:@"importStuff"];
    [self removeObserver:self forKeyPath:@"importStuffFailed"];
}
like image 123
Timur Bernikovich Avatar answered Oct 01 '22 13:10

Timur Bernikovich


There's no guarantee that a viewDidAppear will be matched with a viewWillDisappear every time. This means your KVO registration/unregistration would potentially be unbalanced and non-deterministic. You should perform KVO registration/unregistration in guaranteed pairings like viewDidLoad and dealloc.

like image 23
gurooj Avatar answered Oct 01 '22 14:10

gurooj