UPDATE: Martin R below has provided a very clear (and succinct!) answer that almosts answers my question. I suppose I should rephrase:
Can you think of any reasons why fetching NSManagedObjects that are connected to another NSManagedObject wouldn’t work when calling prepareForDeletion, given that such objects are connected one-to-one to the object being deleted?
I need to be able to call prepareForDeletion so that I can run some entity checking before deciding whether I should delete an object’s children.
Are there any tricks to deleting an object’s children objects in Core Data when it is a one-to-one relationship?
I have a rather complex Core Data model wherein deleting a single NSManagedObject should also delete its children NSManagedObjects via prepareForDeletion. Running a series of debugging NSLog statements immediately prior to deletion reveals that all relationships have been set up properly. However, when actually attempting to delete the object, it seems many (though not all) of these relationships have been lost, as attempting to fetch some (but again, not all) of these objects via NSFetchRequest returns empty arrays.
I can’t seem to figure out any differences between how I fetch the objects that are found versus the objects that are not found, other than that those that are found are inverse to-many relationships while those that cannot be found are one-to-one relationships :-/
To delete the “main” object I simply call [managedObjectContext deleteObject:mainObject];, and within the main object’s private API I have overwritten prepareForDeletion as follows:
- (void)prepareForDeletion
{
// [super prepareForDeletion]; // commented but uncommenting doesn't change results
[MyDataManager deleteChildOneForMainObject:self];
[MyDataManager deleteChildrenTwoForMainObject:self];
[MyDataManager deleteChildrenThreeForMainObject:self];
}
where MyDataManager is a custom NSObject containing only class methods. MyDataManager then searches for corresponding NSManagedObjects in the managed object context via something akin to the following:
- (BOOL)deleteChildOneForMainObject:(MainObject *)mainObject
{
NSFetchRequest *fetch = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"ChildOne" inManagedObjectContext:managedObjectContext];
[fetch setEntity:entity];
[fetch setPredicate:[NSPredicate predicateWithFormat:@"(mainObject == %@)", mainObject]];
NSError *error;
NSArray *childOnesToDelete = [managedObjectContext executeFetchRequest:fetch error:&error];
if (childOnesToDelete.count > 1)
{
NSLog(@"[WARNING] More than one ChildOne for mainObject found; deleting all");
}
NSLog(@"[TEST] Deleting %i ChildOnes", childOnesToDelete.count);
for (ChildOne *childOne in childOnesToDelete)
{
[managedObjectContext deleteObject:childOne];
}
if ([managedObjectContext save:&error]) return YES;
else NSLog(@"[WARNING] Save error for function [deleteChildOneForMainObject:]");
return NO;
}
Again, each NSManagedObject of type “MainObject” has a one-to-one relationship to “ChildOne” and one-to-many relationships with “ChildTwo” and “ChildThree”. “Child One,” “ChildTwo,” and “ChildThree” all have to-one relationships with “MainObject.”
So I finally got IRC to work for me! and a helpful person on the #iphonedev channel provided these insights:
• (Like Martin R said) I should put up with the visual interface for constructing my Core Data model and use the provided “Delete Rule” dropdown menus to create my deletion logic. (In the “Utilities” right-side pane, third tab that looks like a wedge of cheese.) “Cascade” and “Nullify” are the most useful values.
• “Delete Rules” are one-way and unique to each relationship, so you have a fair degree of control.
• Instead of fetching an NSManagedObject that has a one-to-one relationship with a provided NSManagedObject, just use the property. Using a fetch as a “safeguarding” mechanism is stupid and unnecessary since this relation is one-to-one by definition. So if I have
YingandYangobjects, I should just perform[managedObjectContext deleteObject:ying.yang]or[managedObjectContext deleteObject:yang.ying].Ultimately
prepareForDeletionwas only relevant with regards to cascading deletion as per Martin R’s answer.