Does an NSManagedObject retain its NSManagedObjectContext?
Asked Answered
I

3

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
Iambus answered 4/12, 2011 at 20:44 Comment(1)
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.Corned
D
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.

Dariadarian answered 14/8, 2013 at 12:43 Comment(3)
I have noticed the same. Would have been nice if this was documented somewhere...Hemiplegia
@Jeff Page can not be foundJoni
Updated link to docs: Core Data Programming Guide, "Managed Objects and References" section. 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."Francophile
S
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.

Subarid answered 14/1, 2014 at 19:24 Comment(5)
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.Ouidaouija
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.Subarid
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...Ouidaouija
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."Ouidaouija
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.Subarid
H
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

Habitual answered 5/12, 2011 at 4:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.