5

NSManagedObject provides access to its NSManagedObjectContext, but does it retain it?

According to "Passing Around a NSManagedObjectContext on iOS" by Marcus Zarra, "The NSManagedObject retains a reference to its NSManagedObjectContext internally and we can access it."

How does Zarra know this and is he correct?

I'm asking because I want to know if the NSManagedObjectContext will be dealloc'ed in the tearDown method below. (I'm using CocoaPlant.)

#import <SenTestingKit/SenTestingKit.h>
#import <CocoaPlant/CocoaPlant.h>

#import "AccountUser.h"

@interface AccountUserTests : SenTestCase {
    AccountUser *accountUser;
}
@end

@implementation AccountUserTests

- (void)setUp {
    accountUser = [AccountUser insertIntoManagedObjectContext:
                   [NSManagedObjectContext contextWithStoreType:NSInMemoryStoreType error:NULL]];
}

- (void)tearDown {
    [accountUser delete];
}

- (void)testFetchWithLinkedAccountUserID {    
    // Tests go here...
}

@end
ma11hew28
  • 121,420
  • 116
  • 450
  • 651
  • From the context of the quote, I'd say it's likely he means "retains" in the keep sense, not "retain" in the strong reference sense. – Terry Wilcox Dec 05 '11 at 07:45

3 Answers3

9

NSManagedObject DOES NOT hold strong reference to its NSManagedObjectContext. I've checked that on a test project. Therefore, you should keep strong reference to NSManagedObjectContext as long as you use its objects.

eDeniska
  • 101
  • 1
  • 5
  • I have noticed the same. Would have been nice if this was documented somewhere... – Scott Berrevoets Sep 03 '13 at 15:08
  • @Jeff Page can not be found – mtet88 Oct 15 '15 at 16:54
  • 1
    Updated link to docs: [Core Data Programming Guide, "Managed Objects and References" section](https://developer.apple.com/library/prerelease/ios/documentation/Cocoa/Conceptual/CoreData/MO_Lifecycle.html#//apple_ref/doc/uid/TP40001075-CH31-SW1). Quote from docs "By default, though, the references between a managed object and its context are weak. This means that in general you cannot rely on a context to ensure the longevity of a managed object instance, and you cannot rely on the existence of a managed object to ensure the longevity of a context." – Jeff Oct 18 '15 at 00:02
4

Wow, over two years old and no accepted answer here :)

When I wrote that post I did indeed mean it keeps a reference to its associated NSManagedObjectContext. If a NSManagedObject retained the NSManagedObjectContext then it would most likely run into problems.

In either case, whether the MOC is retained by the MO is irrelevant to your application design. If you need the MOC to stay around then you need to retain it (now referred to as a strong reference) or it will go away. What the frameworks do internally is not our problem. We just need to make sure we balance our retains and releases.

Marcus S. Zarra
  • 46,571
  • 9
  • 101
  • 182
  • 1
    Where this matters is how managed objects are passed around, say from one view controller to another. The receiving view controller should retain the managed object **and** its managed object context. Otherwise, it risks the managed object's context from being released, which causes the object to reset its properties and enter a faulted state. This is only an issue if you create multiple contexts. In our app, eg, when we want to show a view controller that edits an object, we create a new managed object context, and pass that. That way, if the user cancels, we can discard the context. – Peyman Apr 17 '14 at 19:01
  • 1
    In that situation the parent controller should be retaining the MOC. Relying on internal retains is asking for trouble. If you want it retained, retain it. Don't rely on the framework. – Marcus S. Zarra Apr 17 '14 at 20:10
  • 1
    I wholeheartedly agree with explicitly retaining the context and not relying on the framework. My point was just that this pattern (retain the managed object + its context) is surprising & counterintuitive to people learning CoreData—if you fail to follow the pattern, your object's state mysteriously disappears. I think it's a matter of personal preference as to which controller retains the context. I prefere the latter because each controller should control its own environment and also because Apple recommendeds it... – Peyman Apr 18 '14 at 00:25
  • The CoreData docs say, "[When you create a view controller, you pass it the context it should use. You pass an existing context, or (in a situation where you want the new controller to manage a discrete set of edits) a new context that you create for it. It’s typically the responsibility of the application delegate to create a context to pass to the first view controller that’s displayed.](https://developer.apple.com/library/ios/documentation/DataManagement/Conceptual/CoreDataSnippets/Articles/stack.html)" – Peyman Apr 18 '14 at 00:26
  • I tend to not rely on the documentation for that level of advice. If you want a vc that only edits one MO and it doesn't need the MOC then I pass in the MO for simplicity since I am going to be controlling the parent MOC from the parent VC anyway. It definitely falls into the realm of opinion. As for the retaining surprising people, it shouldn't. The rule has always been retain what you want to keep around. Of course with ARC that is becoming moot. – Marcus S. Zarra Apr 18 '14 at 14:17
3

Matt,

I think Marcus may have miswrote that a NSManagedObject retains its context. Every NSManagedObject maintains a link to the context. Unless individual objects have an internal retain cycle or are retained outside of their context, then, in my experience, they are all released when the context is released. If they retained the context, then this would almost certainly not be the case.

The above said, you can easily write code to test Marcus' claim. Override -dealloc and log when it is called.

IMO, it is a best practice to retain your context until you are done with it. Depending on an undocumented behavior is probably not wise.

Andrew

adonoho
  • 4,339
  • 1
  • 18
  • 22