NSManagedObject's managedObjectContext property is nil
Asked Answered
K

2

8

I'm trying to create a temporary managed object context, and after a few screens of the user putting in information, I merge that context with the main context (to ensure that there are no "incomplete" objects are inserted). This is how I create my temporary context and how I insert an object in it:

if (!self.someManagedObject) {

    NSManagedObjectModel *model = [NSManagedObjectModel mergedModelFromBundles:@[[NSBundle mainBundle]]];
    NSPersistentStoreCoordinator *storeCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model];
    [storeCoordinator addPersistentStoreWithType:NSInMemoryStoreType configuration:nil URL:nil options:nil error:nil];

    NSManagedObjectContext *managedObjectContext = [[NSManagedObjectContext alloc] init];
    [managedObjectContext setPersistentStoreCoordinator:storeCoordinator];

    self.someManagedObject = [NSEntityDescription insertNewObjectForEntityForName:@"SomeObject" inManagedObjectContext:managedObjectContext];
    NSLog(@"%@", self.someManagedObject.managedObjectContext);
}

This is a part ofviewDidLoad. In the console it shows that managed object context has a value.

However, right after this if statement (even within viewDidLoad, self.someManagedObject.managedObjectContext is nil. I can see why the local variable would not be available anymore (it simply goes out of scope), but the managed object's property should still be set, right?

I know I can create a property to store the managed object context, but I'd rather get it to work this way.

Kirov answered 2/8, 2012 at 23:0 Comment(4)
is someObject the same as someManagedObject?Queston
Oops, yeah. I put someObject first, but then wanted to clarify it's an NSManagedObject.Kirov
You've checked that self.someManagedObject is non-nil? Supposing insertNewObject... failed or your property is peculiar, that would explain what you're seeing.Wonted
Yep, self.managedObject still has the right value.Kirov
K
21

I recently ran into the same problem again, although it was in a different situation. I needed a temporary managed object context, completely separate from the main one, but I again ran into the problem of it disappearing after it goes out of scope. This time I decided to investigate further, and I ultimately realized that managedObjectContext is not a property of NSManagedObject, but a method. This means one of two things:

  1. If it uses a property in the underlying implementation, that property will not hold a strong reference to the context
  2. If the managed object context is derived in some other way, it will also not hold a strong reference to that context.

In either case, the context has no strong references, goes out of scope, and the NSManagedObjects have a nil managedObjectContext.

The solution was to simply keep the context around by creating a strong property for it.

Kirov answered 19/10, 2013 at 19:16 Comment(3)
Do you know why this is the case? (I have a separate SO question for that...)Rau
The link the description is not working anymore. More data can be found here.developer.apple.com/documentation/coredata/nsmanagedobject/…Rateable
managedObjectContext is defined as unowned(unsafe) open var managedObjectContext: NSManagedObjectContext? { get } in NSManagedObject supporting the above in that the property won't hold a strong reference.Cannell
L
-3

I do not see why you would need a second managed object context. IMHO, you are introducing complexity into your app that does not serve any particular purpose.

Insert the new object into the main context. Let the user input his data. If he breaks off, simply call

[managedObjectContext rollback];

or, if the user finishes and all the data is validated, call

[managedObjectContext save:nil];
Lurcher answered 4/8, 2012 at 11:18 Comment(6)
That seems like a good solution too, but how far back does rollback go? To the last save? I'm kind of relying on auto-saving, so I would have to manually put in calls to save then (which isn't a problem, but I'd have to know).Kirov
Last save - it can be a bit more complicated than that, but only in special situations. - Plus, I was not aware of "auto-saving". Certainly better to do it explicitly.Lurcher
I have one problem with doing it this way: I have to check for all possible ways that the user could avoid filling out all the information. Instead of checking whether the user did something "wrong" (as in, the process was interrupted), I want to be able to save when the process was completed. By process I mean "going through the screens in which the user enters information". I don't want to have to call rollback for every possible interruption.Kirov
That's also OK. Just keep track of the data you want to save, and save it when the user finishes - throw it away when the user has definitely broken off the process. However, in principle that is what rollback does as well. A second MOC will not help you here.Lurcher
The problem is with auto-saving though. I have another app that uses Core Data, and I never call save there, yet all my data is persisted. I can't find any documentation that says it has an auto-saving mechanism, but in my experience it does do that. Since it does that, I can't just throw out data, as it's already put in the persistent store for me.Kirov
Another problem is with split views on the container. If a user adds a new record, you don't want it showing up in the master table view until they hit save and it has been validated.Meill

© 2022 - 2024 — McMap. All rights reserved.