0

Recently I have gotten some very strange crashes on HockeyApp:

Application Specific Information: Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'An instance 0x13ef90530 of class FPPhoto was deallocated while key value observers were still registered with it. Current observation info: NSKeyValueObservationInfo 0x13e9e8bb0 ( NSKeyValueObservance 0x13ef36810: Observer: 0x13e5a95f0, Key path: fractionCompleted, Options: New: YES, Old: NO, Prior: NO> Context: 0x0, Property: 0x13ef795d0 )'

I understand the basis of the crashreport and this can very well be true as I have KVO observers all over the place in my app, also connected to objects of type FPPhoto

The strange thing I wonder about is the name of the parameter: (Key path: fractionCompleted) We actaully have a parameter called fractionCompleted, but that is in a totally different place in the application. We add KVO to fractionCompleted to track upload progress. fractionCompleted KVO listener is though never added to any object of kind FPPhoto in the code.

I guess either it's the crash report that got the parameter/class names mixed up or can it be worse, -> some kind of memory mixup at runtime to make KVO attach to the wrong object?

Any ideas how this can happen?

knutigro
  • 1,082
  • 2
  • 10
  • 20
  • 1
    I would reevaluate your code; it's much more likely an error in your code than in the bug reporting or KVO system. Just sayin' – trojanfoe Nov 06 '15 at 14:02

1 Answers1

1

You should consider adding two symbolic breakpoints on:

-[NSNotificationCenter addObserver:selector:name:object:]

and

-[NSNotificationCenter addObserverForName:object:queue:usingBlock:]

With the condition:

(BOOL)[@"fractionCompleted" isEqualToString:(id)$r8]

and

(BOOL)[@"fractionCompleted" isEqualToString:(id)$rdx]

Then set an action as a Debugger Command:

po $rdx

and

po $rcx

If you're curious about why the registers change, that is because OS X follows the System V ABI for register calling conventions. Arguments for a method go into:

rdi, rsi, rdx, rcx, r8, r9

In that argument order. Because Objective-C messages get compiled into objc_msgsend(receiver, selectorname, argument1, argument2, argument3, argument4)

We have to change the registers being compared because those 2 -addObserver signatures differ in the location of their arguments for the notification name and the observer object.

Using these breakpoint will help you identify which objects get registered as an observer, so you can make sure they are deallocated & remove observation properly.

EDIT: Just realized that you are not using NSNotificationCenter, just KVO. But I don't want to delete my answer, so I'm just going to leave it. It's still applicable, you just need to change the symbol you break on to - addObserver:forKeyPath:options:context:, and you will need to add more conditions because otherwise you will hit that breakpoint 10 times a second.

A O
  • 5,516
  • 3
  • 33
  • 68