NSManagedObject remains a malfunction

My situation : Assuming I have a Person class (subclass of NSManagedObject). Each time the user clicks the button, a new instance of Person will be created and added to the global NSMutableArray. Also, a new child instance of Person will be added to the child context, for example as follows:

 NSManagedObjectContext *childContext = [[NSManagedObjectContext alloc] initWithConcurrencyType: NSPrivateConcurrencyType]; [childContext setParentContext: _mainContext]; 

Also, when I click the button, I save the context: (this is a little more complicated, but follows this structure)

 [childContext performBlock:^{ [childContext save:nil]; [_mainContext save:nil]; }]; 

After clicking two or more times (not sure if this depends on the total number of clicks), the button objects in my array become fault .

According to the docs: access to the property of the fault object should load the persistent object.
Even when I access the property of my NSManagedObject, the object is still faulty, and the property is nil .

Why is there an error of objects in my array and how do I access the property of the error object?

Edit

When loading the UIViewController, I retrieve all existing objects from the data store:

 -(NSArray*)fetchPersons { NSManagedObjectContext *context = [self managedObjectContext]; //this is _mainContext, it is created with initWithConcurrencyType:NSMainQueueConcurrencyType NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; NSEntityDescription *description = [NSEntityDescription entityForName:@"Person" inManagedObjectContext:context]; [fetchRequest setEntity:description]; NSPredicate *predicate = [NSPredicate predicateWithFormat:@"key = %i", aCondition]; [fetchRequest setPredicate:predicate]; return [context executeFetchRequest:fetchRequest error:nil]; } 

I am using this NSArray from fetchPersons to populate NSMutableArray.

Creating a new Person object:

 -(Person*)createPerson { NSManagedObjectContext *childContext = [[NSManagedObjectContext alloc] initWithConcurrencyType: NSPrivateQueueConcurrencyType]; [childContext setParentContext:[self managedObjectContext]]; Person *person = [NSEntityDescription insertNewObjectForEntityForName:@"Person" inManagedObjectContext:childContext]; return person; } 

I am not sure how to handle objects using òbjectID`. I use childContext as a temporary context. Sometimes I need an instance of Person, but I don’t want to store it in persistent storage (or insert it into the main context at the beginning).

After all these steps, I have all the objects in my NSMutableArray. I get the nil properties (error object) after creating some objects and try to write their attributes ( person.name or something else).

+4
source share
1 answer

NSManagedObject maintains a close relationship with the NSManagedObjectContext on which they were created. The specific reasons for this are that the managed objects are always mutable, so they may need to write back to the repository, and they expect a future error. The master data obviously may not load the entire persistent storage into memory, but may deal with your future arbitrary crawl of the graphic or with low memory warnings.

(aside: this is also the closest reason why Core Data objects cannot be used on anything other than the thread / queue on which they were created; these are contexts and various bits of implicit communication between contexts and objects that are not safe)

In practice, this means that you should not let the managed entity outlive your store.

So that you can send objects back and forth between different agents with different contexts, Apple implements NSManagedObjectID , which is a unique identifier for any managed object. This is a completely opaque class, but for information, if you have a SQLite store, then this is a link to the corresponding table and row; if you have one of the other types of storage, then this is similar to a pointer to a location in a store. It does not carry any of the data of the object.

So what you usually do is call the objectID object, and the context that was created in it is still alive. Then you can pass it on to someone else who wants it. They will then use [myManagedObjectContext -existingObjectWithID: error:] to get a new copy of the managed entity that they can safely use. A new copy will be attached to this context, and not to the original, therefore it will be safe whenever and for how long this context is safe, not the original.

The only potential surprise is that when you first insert an object, it receives only the temporary identifier of the object. This is because Core Data likes to load things that need to be inserted into the repository, and then insert them immediately right away, only when you request a save.

For your purposes, you do not want to pass the identifier until you save it, since the object will not exist in the parent repository. So the point is partially academic, but suppose you wanted to distract identifiers for some other reason, you might also consider using the -obtainPermanentIDsForObjects:error: context, which can be much faster than the actual save, depending on the type of store you have. and certainly never will be slower.

+17
source

All Articles