views:

1546

answers:

3

I have a bug I'm struggling to track down. I believe what's happening is that I'm deleting an object from the underlying database whilst another managed object context (in another thread) has a fault on it and gets the 'NSObjectInaccessibleException' when it tries to fulfil the fault.

The scenario is that I have a view accessing the data through one context meanwhile in the background, another threat is purging out of date records from the store. The background thread should only be purging objects which are not required by the view - this obviously isn't the case but I'm having trouble tracking down exactly what happens. By the time I see the defect, it's too late and it is a relatively rare defect that mainly only happens in the field.

Hence my question: Are there any tricks I'm missing when debugging CoreData - can I track lifetimes of objects from one context in another? I.e. when I delete my object is there an easy way to see if any other contexts have a reference to that same object? Using that, I could build some test code to check my logic and find the error.

+1  A: 

What is the second context doing when it tries to fault in the object which has been deleted from the persistent store?

This sounds like a bug which may have 2 parts: you aren't merging changes from your peer context, and you have a logic bug which is causing you to use an object in thread B which has been deleted in thread A.

Typically you'll want to merge changes from a peer context using -[NSManagedObjectContext mergeChangesFromContextDidSaveNotification:].

Jim Correia
I think there are two bugs here and I agree with what they are :-( what I need is a way of tracking them down.
Roger Nolan
Are you merging changes from your peer contexts? For debugging purposes you can log deleted objects whenever a context is saved. If you know what all of the other extant contexts are, you can also examine the objects registered with those contexts, but you'll have to do so in a thread safe manner.
Jim Correia
You're right. I decided that I need to fix the whole threading situation to resolve this defect. It's not trivial but probably good for my health.
Roger Nolan
+3  A: 

I encountered this error earlier and the culprit was that I was cleaning up (completed released) my context and then later tried to access an object (previously) managed by that context.

In my case, the context was a "scratch" context that goes away when the view was closed. However, I had a background job that the view had spawned that wanted to update the object.

I ended up making an accessor for the managed object that returned nil when [managedObject isFault] was true. Then in my code I was checking the value of that accessor selector to make sure I had a valid object to work with (say when my background job finally finished its work).

I'm pretty new to Core Data, so there's probably a better/smarter way to do this, but I think it fixed the issue for me.

Jason
Jason, thanks for bringing this back to my attention. I recently fixed my error it was a combination of cleanup and a MapKit - map views keep their delegate too long. In your case, you should probably not be accessing the same NSMAnagedObject context from you background thread - CoreData is not thread-safe. Instead you should pass an NSManagedObjectReference to your background task.
Roger Nolan
Yeah, you're definitely right. In my case I was jumping back on the main thread (where I create all contexts) before actually editing the object, but that's still no good when its context has gone bye-bye.
Jason
What is this "NSManagedObjectReference" that you speak of?Doesn't exist, according to docs...
Adam
A: 

The solution was a combination of cleanup and this mapkit bug. a map view was holding onto its delegate after I had released my NSManagedObjectContext. Mapkit asked the delegate for the co-ordinates of an annotation and my delegate object tried to query an object that was in a released context (similar to Jason's problem).

The fix was as described in Jake's blog post - set the delegate to nil when you are finished with the map view.

Roger Nolan