0

I'm looking through my crash reports in TestFlight and the most frequent crash is:

Cannot remove an observer "ListViewController 0x1d590500" for the key path "batchImageDownloadingInProgress" from "ListArchiver 0x1d5b83b0" because it is not registered as an observer.

In ListViewController:

- (void)viewWillAppear:(BOOL)animated
{
    ...

    [[WanderlistArchiver sharedArchiver] addObserver:self forKeyPath:@"batchImageDownloadingInProgress" options:NSKeyValueObservingOptionNew context:nil];
}

// **** the error happens in here ****
- (void)viewWillDisappear:(BOOL)animated
{
    ...

    [[WanderlistArchiver sharedArchiver] removeObserver:self forKeyPath:@"batchImageDownloadingInProgress"];
}

If I set up the observer in viewWillAppear (and don't touch it anywhere else in the code), why is it not still registered when viewWillDisappear runs? This has only happened 5 times in the last 90 days, but I'd still like to understand why this is happening.

djibouti33
  • 12,102
  • 9
  • 83
  • 116
  • Be sure to call `[super viewWillAppear:animated]` and `[super viewWillDisappear:animated]`. I don't think it's your issue but could cause unexpected results. – Chris Wagner Jan 16 '13 at 18:17
  • Yeah, I actually do that, but left it out to make my question more focused. – djibouti33 Jan 16 '13 at 18:20
  • How is your sharedArchiver singleton handled? Is there any chance you might be calling removeObserver on a different instance than addObserver was called? – Taum Jan 16 '13 at 18:32
  • I don't think so. Here's my code (sans formatting unfortunately): + (WanderlistArchiver *)sharedArchiver { static WanderlistArchiver *__instance = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ __instance = [[WanderlistArchiver alloc] init]; }); return __instance; } – djibouti33 Jan 16 '13 at 18:41

2 Answers2

1

Most likely the problem is that viewWillDisappear: is being called more than once per call to viewWillAppear:. Since this only seems to be happening rarely, there must be some strange sequence of events resulting in this happening.

One possible workaround, if you can't reproduce the issue, is to add a BOOL ivar. Set it to YES in viewWillAppear: when you add the observer. In viewDidAppear:, check if it is set or not. If set, then set it to NO and remove the observer. If not set, then you know not to remove the observer.

rmaddy
  • 314,917
  • 42
  • 532
  • 579
1

You should make sure the context is the same. In your remove statement, you are using the method that does not use context. Use a context variable instead of nil and make sure that it is the same in the add and remove statements.

Look at this question for more detailed explanation.

Community
  • 1
  • 1
Mundi
  • 79,884
  • 17
  • 117
  • 140
  • Thanks for the link and suggestion. That answer assumes some class is observing it's own property. I have one object observing a property on another object. It seems like it'd be much more difficult and confusing to set up the observation inside ListArchiver#setBatchImageDownloadInProgress. 1) I don't know the exact instance of ListViewController, and 2) It'd be complicated to share the same context (static address) across two objects. Perhaps I'm missing something; thoughts? – djibouti33 Jan 16 '13 at 18:30
  • I think you can just have each observing object have its own context which would make this trivial. – Mundi Jan 16 '13 at 20:40