This is a test on part of Apple's Core Data PG, which I quote here
- You started with a strong reference to a managed object from another object in your application.
- You deleted the managed object through the managed object context.
- You saved changes on the object context. At this point, the deleted object has been turned into a fault. It isn’t destroyed because doing so would violate the rules of memory management. Core Data will try to realize the faulted managed object but will fail to do so because the object has been deleted from the store. That is, there is no longer an object with the same global ID in the store.
So I setup a test project to see if it is the real case.
I'm using MagicalRecord to save some troubles creating MOCs, the code is based on a Core data model Class named "People"
@interface People : NSManagedObject
@property (nonatomic) int64_t userID;
@property (nullable, nonatomic, retain) NSString *name;
@end
In the test part, I wrap the MOCs MagicalRecord created into backgroundMOC and UIMOC so that those who are not familiar with MagicalRecord won't be confused.
UIMOC is BackgroundMOC's child and will merge backgroundMOC's changes by listening to NSManagedObjectContextDidSaveNotification backgroundMOC send out.
The "saveWithBlockAndWait" is just a wrapper around "performBlockAndWait". So here comes,
[[self backgroundMOC] MR_saveWithBlockAndWait:^(NSManagedObjectContext * _Nonnull localContext) {
People *people = [People MR_createEntityInContext:localContext];
people.userID = 1;
people.name = @"Joey";
}];
People *peopleInMainThread = [People MR_findFirstInContext:[self UIMOC]];
NSLog(@"Before delete, name = %@", peopleInMainThread.name);
[[self backgroundMOC] MR_saveWithBlockAndWait:^(NSManagedObjectContext * _Nonnull localContext) {
People *people = [People MR_findFirstInContext:localContext];
NSLog(@"Deleting, name = %@", people.name);
[localContext deleteObject:people];
}];
NSLog(@"After delete, name = %@", peopleInMainThread.name);
[[self UIMOC] save:nil];
NSLog(@"After save UIMOC, name = %@", peopleInMainThread.name);
The NSLog result is
Before delete, name = Joey //As expected
Deleting, name = Joey //As expected
After delete, name = Joey //Shouldn't it be nil already?
After save UIMOC, name = null //As expected
This result seems to state that Merge from parent MOC won't make model objects fault, which could lead to some hard-to-find bugs or instead tedious checking codes everywhere. Again with the people object. I'll have to do things like this
- (void)codesInSeriousApp
{
[[self backgroundMOC] MR_saveWithBlockAndWait:^(NSManagedObjectContext * _Nonnull localContext) {
People *people = [People MR_createEntityInContext:localContext];
people.userID = 1;
people.name = @"Joey";
}];
__block People *people = nil;
[[self UIMOC] performBlockAndWait:^{
people = [People MR_findFirstInContext:[self UIMOC]];
}];
[self sendHttpRequestViaAFNetworking:^{
//this block is executed on main thread, which is AFNetworking's default behavior
if ([[self UIMOC] existingObjectWithID:people.objectID error:NULL])//[people isFault] would be NO here, and people's properties stay still.
{
//do something
}
else
{
//the people object is gone
//maybe some codes on another thread deleted it and save to the backgroundMOC
//the UIMOC merge the changes sent by notification, but the people object is still NOT FAULT!
}
}];
}
As far as I can tell, for any model non-fault object in a specific MOC, say MOCA, the object won't be fault until [MOC save:&error] called all the way down to the persistent store. What really confuse me is, if Another MOC, already know that the object is fault by doing the saving chain, and MOCA merged changes that very MOC send out, how come the object in it is still non-fault? Am I misunderstood or anything? Any reply would be appreciated.
Thx in advance :)