4
votes

Im constantly being given an error that reads *** -[NSKeyValueObservance retain]: message sent to deallocated instance 0x86c75f10. I have tried running the Zombies template and here is the screenshot of what it provides.

enter image description here

It points to a managedObject, and I'm having trouble figuring out where the object is being deallocated. Here is the block of code that the compiler takes me to after each crash.

- (void)setIsFavourite:(BOOL)isFavourite shouldPostToAnalytics:(BOOL)shouldPostToAnalytics;
{
    // check whether we need to generate preferences objects just in time
    if(!self.preferences && !self.series.preferences /*&& isFavourite*/)
    {
        if(self.series)
        {
            [self.series addPreferencesObject];
        }
        else
        {
            [self addPreferencesObject];
        }
    }

    //Crash In here
    self.preferences.isFavourite = @(isFavourite);
    self.series.preferences.isFavourite = @(isFavourite);

EDIT: If you need to see a larger size of the image here is a larger resolution link.

2
Please post more of your managed object implementation. Are you overriding an accessor? Are you accessing a primitive value? CoreData uses KVO extensively . It appears that there are unbalanced calls to some of CoreData's internal methods which is very unusual and appears to be the source of the problemquellish

2 Answers

5
votes

OK, I hit something similar and found a way to debug this kind of issue with NSKeyValueObservance. To debug, do the following:

  1. In Xcode, open the "Breakpoint Navigator".
  2. Add a new symbolic breakpoint with: -[NSKeyValueObservance _initWithObserver:property:options:context:originalObservable:]
  3. To that breakpoint, add an action and set it to "Debugger Command".
  4. Set the following command: expr (void)NSLog(@"observer <0x%p>: %@ <%p>, property: %@", $arg1, (id)NSStringFromClass((id)[(id)$arg3 class]), $arg3, (id)$arg4)
  5. Click the "Automatically continue after evaluating expression".

Now you can run your application and take the steps necessary to reproduce your crash. And yes, you'll want NSZombies enabled. Note: it's going to run slow and you're going to get a ton of debug output, but just be patient. It'll get there eventually.

When you hit the crash when trying to message a deallocated NSKeyValueObservance, you'll be presented with the address of the original object. Highlight the address and hit cmd-e to enter the text in the search buffer. Then hit cmd-g find the next occurrence of the string in the debugger output. You're going to potentially find the address a couple of times, so look for the address that follows the observer <0x?????> output. The output on that line should tell you what object is being observed and for which property.

In my case, when I figured this all out, it turned out that I was observing a synthesized property that depended on an object in array and during a certain operation, the order of the objects in the array changed without doing the correct KVO notifications, and that caused my crash.

0
votes

Are you using manual reference counting? If so, why? Convert your app to ARC. Manual reference counting is painful at best, and ARC is much better.

I am an experienced iOS and Mac OS developer and can do either, but I far prefer ARC. It's much less fussy and error-prone.

There is a feature built into Xcode that will convert your project to ARC for you. You might have to do some cleanup afterwords, but it's worth it.

If you do that your problem will likely go away.

As to the specifics, your screenshot is far too small to be able to read it. You will need to post a full-sized image if you want somebody to try to figure out what's going on.

However, in broad terms it sounds to me like you have an autorelease bug.

in manual reference counted code, lots of system method return objects that are "autoreleased." That means that when you receive them their retain count is positive (usually 1) so they stick around. However, they have been added to the "autorelease pool," which means that they are going to be released on the next pass through the event loop if nobody retains them first.

When you receive an autoreleased object you should either accept that it will be released once your current method returns, or retain it.

If you are trying to write Core Data code using manual reference counting and don't understand this then you are setting yourself up for failure.

Core Data is pretty complex, and you should have a solid understanding of Cocoa memory management before attempting to write a program that uses it, especially if you're using manual reference counting.