iOS KVO - Cannot remove an observer
Solution 1
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
.
Solution 2
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"];
}
Related videos on Youtube
![j2emanue](https://i.stack.imgur.com/3IiNW.png?s=256&g=1)
Comments
-
j2emanue almost 2 years
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 ?)
-
luk2302 almost 9 years@vib no no no no. NO. Do I have to explain that that is really very very bad practice? That does not solve anything and will just cause your program to not work as intended and crash at some later point without indication to why. Not logging exceptions is a very bad idea as well. An exception is an indication that something went wrong that you should take care of and not just ignore.
-
gurooj almost 9 yearsNo, there's no guarantee that a viewDidAppear will be matched with a viewWillDisappear every time. It is very bad practice to handle KVO in these methods. Do not attempt! Do it in more documented pairings like viewDidLoad/dealloc
-
guroojThis is not a safe way to handle KVO. If your app is interrupted by a phone call, then viewWillDisappear won't get called, but viewDidAppear could get called again when the app relaunches. There are many other less than ideal possibilities. You should consider using more reliable methods to add and remove observers (viewDidLoad, dealloc, etc)
-