views:

30

answers:

2

I have a common application pattern: user enters data in the main view controller, then views it in a table in a modal view controller, where rows can be deleted or modified. I was following the general design strategy from the Stanford iPhone course, but somewhere things went off the rails and all I've been getting is SIGABRT's and exceptions like "Illegal attempt to establish a relationship 'xyz' between objects in different contexts."

As in the Stanford course, I use a singleton class called "Database" which should return the same context whenever requested. So the first commands in my viewDidLoad method on the main view controller are:

 dbsingleton = [Database sharedInstance];
 nmocontext = [dbsingleton managedObjectContext];

nmocontext is an ivar I use throughout the view controller. When the user wants to see the other view controller, with the table, I alloc-init it, then present it modally. (It has an NSFetchedResultsController that supplies the data from my store.) I've tried various strategies here:

  • I've made the NSFetchedResultsController a retained property set by the main view controller
  • I've made the NSManagedObjectContext a retained property set by the main view controller; and
  • I've used the singleton internally by repeating those two lines of code above at the beginning of the table view controller's viewDidLoad method.

Whichever I go with, the one problem I just can't solve is that after the user closes and deallocs the table view controller (and its NSFetchedResultsController), I start getting crashes in the main view controller when the store is accessed (like the "Illegal attempt" error mentioned above).

What are best practices for dealing with this common application pattern? I am still hoping to make this application iPhone SDK 3.x compatible, but I do seem to have fewer crashes when I'm using iOS 4 -- if there are underlying issues with 3.x that are causing me problems, please let me know and I may target iOS 4 only.

Thank you!

A: 

This is just a guess but I assume the following problem for your crashes after closing the tableview:

You declared a property

@property (retain, nonatomic) NSManagedObjectContext* nmocontext;

do you properly release the ivar nmocontext in dealloc? If yes your problem is the assignment

nmocontext = [dbsingleton managedObjectContext];

This never retains nmocontext within your viewcontroller but you release it on dealloc.

Second:

"Illegal attempt to establish a relationship 'xyz' between objects in different contexts."

This is not a memory management issue, but you probably created another new context to add objects (like in the apple core data iphone samples) and tried to set a NSManagedObject as relationship from a different context.

Martin Brugger
This is helpful... Removing the release message helps on the iOS 4.0 simulator but I still get crashes on my 3.x test device. I checked out your profile and you look to be brilliant with CoreData -- what would your overall strategy be for this type of app? I'm wondering if I'm overcomplicating things with the singleton class? What's the best approach for creating contexts and FetchedResultsControllers when you need to access the same CoreData store from different view controllers?
ed94133
Marcus S. Zarra recommends dependency injection for sharing the context. This question has already been discussed here: http://stackoverflow.com/questions/3174610/passing-managedobjectcontext-along-to-view-controller-hierarchy
Martin Brugger
Thank you. I got rid of the singleton and am passing the context in as a property throughout. This has been helpful in preventing runtime crashes. However, when I write to the cache I somehow disturb it -- on subsequent readings I get a fatal error around my persistent cache. I think I should this post as a separate question. Thanks.
ed94133
A: 

It sounds like you don't have your singleton properly configured.

A singleton should override release to do nothing such that when it is sent a release message nothing happens. If you do not override release then any random piece of code anywhere in the app can kill the singleton and defeat the entire purpose of using a singleton. The next time you call singleton, you actually get another new object which in this case also returns a new managed object context.

See Cocoa Fundamentals Guide: Creating a Singleton Instance.

Singletons are powerful and flexible but very easy to do wrong. They are so easy to screw up that many experienced developers simply refuse to use them. If don't have experience with them, don't use them when you are just starting out.

TechZen