views:

191

answers:

2

I am trying to debug a very nefarious problem with some iPhone Core Data code.

The setup is this: I have a thread which exists to poll a web service and send its results via NSNotification to the main thread (passed in the userDict, a bunch of strings and NSNumbers). I'm using Tim Hatcher's notification library to pass to the main thread.

NSDictionary* userDict = [Message userDictFromXML:el];
if (userDict != nil)
{
   [[NSNotificationCenter defaultCenter] postNotificationOnMainThreadWithName:@"InsertMessage" object:nil userInfo:userDict];
}

The main thread receives the userDict, then proceeds to extract its values and insert them into a new managed object. So far so good.

I run into problems with this however, but not immediately. After the thread has posted its results to the main thread, and it save a new object into the context, I can perform a certain series of operations (including a NSFetchRequest and a couple of relationship assignments) which results in a EXC_BAD_ACCESS when trying to access one of the properties of the fetched managed object.

The other funny thing is that I can make the problem go away. I can do this by putting a single [userDict retain] in the thread before I put it inside a NSNotification to be posted into the main thread to be saved into the managed object. It doesn't matter if I firewall the objects from each other by creating a new NSString as soon as I receive the values in the receiving thread, it will still crash without that retain.

NSDictionary* userDict = [Message userDictFromXML:el];
if (userDict != nil)
{
   [userDict retain]; // NOW THIS WORKS (???)
   [[NSNotificationCenter defaultCenter] postNotificationOnMainThreadWithName:@"InsertMessage" object:nil userInfo:userDict];
}

What gives ???

A: 

It sounds to me that you need to retain the objects while adding them to the ManagedObject from the Dict. I suspect that adding the retain before you send it through the notification is over retaining, but you are missing a retain on the other side so it is balancing out.

Joe Cannatti
Shouldn't have to, I have 'retain' specified on all the properties of my managed object (using the standard generated class, nothing fancy)
sehugg
Ah okay. I'm not sure then. Maybe a missed retain somewhere even earlier?
Joe Cannatti
+2  A: 

So the problem is really with properties going into the managed object, right? The reason the retain fixes things is because that dictionary never gets released, that means whatever else is over-releasing your object is able to do so without crash, and in the end you have a dictionary with a bad pointer in it (since your object has been released).

If you have Snow Leopard, try running with NSZombieEnabled turned on, and use the ObjectAlloc instruments tool. When the zombie gets freed, you can click and find a list of all the places the object was retained and released.

Kendall Helmstetter Gelner
ARGHH! A single [retain] was the culprit. From now on, everything is a (retain) property :^P Thanks for prodding me in the right direction. I knew Instruments had something useful, I just didn't realize how far down the rabbit hole it took you.
sehugg