Reputation: 1193
I am trying to understand iOS Core data transient properties and am having trouble understanding some behavior.
Setup
I have two contexts a Main and a Private context. I call them mainContext and threadedContext .
The threaded context is the parent context and the main context is the child context. (I did it this way because my threaded context alters the model far more frequently than my main thread and UI do.
I have transient properties who's value I need to pass through contexts.
I find that sometimes I loose the value and sometimes I don't depending on how I run things.
Sample
This code has been simplified to show the problem. I have a Person object. The Person object has a transient entity called "other" of which you will see I assign an Other object to it that has a couple simple properties, nothing more.
- (void)case1
{
NSManagedObjectContext *mainThreadContext = [AppDelegate appDelegate].mainThreadContext;
NSManagedObjectContext *threadedContext = [AppDelegate appDelegate].threadedContext;
__block NSManagedObjectID *objectID = nil;
[mainThreadContext performBlockAndWait:^{
//create
Person *aPerson = [self createAPersonOnContext:mainThreadContext];
//setup
Other *other = [[Other alloc] init];
aPerson.other = other;
aPerson.other.favoriteColor = @"Blue";
aPerson.other.city = @"Provo";
//save
NSError *error = nil;
[mainThreadContext save:&error];
objectID = aPerson.objectID;
NSLog(@"%@",aPerson);
}];
}
When I retrieve the Object like this the person.other property is still set (note that I am saving AFTER I retrieve the object:
[threadedContext performBlockAndWait:^{
Person *aPerson = [self getPersonOnContext:threadedContext withID:objectID];
NSError *threadedError = nil;
[threadedContext save:&threadedError];
NSLog(@"threaded %@", aPerson);
}];
When I retrieve the Object like this the person.other is no longer set (note that I am saving BEFORE I retrieve the object)
[threadedContext performBlockAndWait:^{
NSError *threadedError = nil;
[threadedContext save:&threadedError];
Person *aPerson = [self getPersonOnContext:threadedContext withID:objectID];
NSLog(@"threaded %@", aPerson);
}];
I've tried different things including refreshObject:mergChanges: I've tried to watch when objects fault but that didn't appear to be helpful. Are transient values stored in a given context (assuming I have saved, or maybe not given the issue I am seeing) even if no model object is currently instantiated?
For those who feel they need more... The method getPersonOnContext:WithID looks like this:
- (Person *)getPersonOnContext:(NSManagedObjectContext *)context withID:(NSManagedObjectID *)ID
{
__block Person *person = nil;
[context performBlockAndWait:^{
person = (Person *)[context objectWithID:ID];
}];
return person;
}
The createAPersonOnContext: looks like this:
- (Person *)createAPersonOnContext:(NSManagedObjectContext *)context
{
__block Person *person = nil;
[context performBlockAndWait:^{
person = (Person *)[NSEntityDescription insertNewObjectForEntityForName:@"Person"
inManagedObjectContext:context];
person.firstName = @"matt";
person.lastName = @"ZZZ";
}];
return person;
}
I just wanted to hide this code to help bring attention to the problem it self.
If you want to experiment with this I have it on github: https://github.com/mcmurrym/CoreDataBehaviors
Update:
It appears that when I save before using the ID to retrieve the object in the threaded context that it is faulting the Person object which destroys the transient values. If I retrieve the object in the threaded context before saving, the transient value is preserved because the object is not faulted.
Upvotes: 2
Views: 2355
Reputation: 4339
maxpower,
Transients are quite simple. They are properties that are always non-existent in the backing store. Hence, the fact that you ever see them is because you are using a child MOC and have externally assigned those values. To ensure that a transient is always valid, you need to consider implementing the -awakeFromInsert
, -awakeFromFetch
, -prepareForDeletion
, -didTurnIntoFault
and -willTurnIntoFault
methods.
Andrew
Upvotes: 5