Reputation: 731
I'm using CoreData to persist a list of messages in a conversation.
Conversation is a managedObject that has an array of Messages. In one scenario, I'm trying to delete all the messages in a conversation.
for (UQMessage * message in self.tempConversation.chatMessages){
[self.tempConversation.managedObjectContext deleteObject:message];
error = nil;
[self.tempConversation.managedObjectContext.persistentStoreCoordinator lock];
if (![self.tempConversation.managedObjectContext save:&error]) {
NSLog(@"Can't Delete! %@ %@", error, [error localizedDescription]);
return;
}
[self.tempConversation.managedObjectContext.persistentStoreCoordinator unlock];
}
When I check for
self.tempConversation.chatMessages.count
Nothing changes.
Everything works perfectly well when I try to add messages, and when I delete the conversation itself. But I can't seem to delete a single message.
Is it even possible to do since I'm not trying to delete the managed object itself but another object inside it? If not, Anyway around it?
EDIT:
Messages is an NSOrderedSet inside Conversation. I've found this works (taken from this thread):
NSMutableOrderedSet *mutableItems = (NSMutableOrderedSet *)items.mutableCopy;
[mutableItems addObject:anItem];
items = (NSOrderedSet *)mutableItems.copy;
though I'm not sure if this is the way to go.
Upvotes: 0
Views: 510
Reputation: 1892
You should never, ever mutate the array you're iterating over. Per the fast enumeration docs: "It is not safe to remove, replace, or add to a mutable collection’s elements while enumerating through it. If you need to modify a collection during enumeration, you can either make a copy of the collection and enumerate using the copy or collect the information you require during the enumeration and apply the changes afterwards."
The result of mutating an array during enumeration is undefined, and my guess is core data might be just tossing up its hands and not doing anything. The reason why the mutable copy works is because you're working on a copy, not the set you're enumerating over.
I would rewrite your logic to follow the guidelines laid down in the enumeration docs, and make your changes outside of the loop.
EDIT: Additional Thoughts
Why are you locking & unlocking the persistent store? It handles that itself.
You can probably call delete safely inside the for in (but I wouldn't) and then call save outside, since save is what actually does the deletion.
More Thoughts
(Transcribing from a comment) - After thinking about this for a few days and then coming back, my guess is the reason you're not outright crashing is fast enumeration is doing a deep copy on the relationship array you're working on, because calling save on a MOC is going to increment an internal version, and then should return all existing managed objected to a faulted object to be re-fetched on next access. Really this code you've got here is actually quite dangerous from an "application health" perspective.
Upvotes: 1
Reputation: 3359
First, about the answer by Matt S., you are not modifying self.tempConversation so you don't have to worry about mutating the array while iterating.
On the other hand, if your problem is that self.tempConversation.chatMessages.count doesn't change. That is normal. You are deleting objects from the NSManagedObjectContext. But the array is not modified. So, the array still have the managed object BUT that managed object is deleted. Is that easy. It is a zombie managed object because it has been deleted from the MOC. Nevertheless the object has not been removed from the array. So you have a managed object with the property deleted set to YES. And it is not part of the MOC any more.
Upvotes: 2
Reputation: 1136
If you look at the documentation for core data relationships, I think you'll find the easier thing to do is just set the relationship delete rule for the relationship to "Cascade". This will remove all the messages for you when you delete the conversation. Here's the reference: https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CoreData/Articles/cdRelationships.html#//apple_ref/doc/uid/TP40001857-SW1
Upvotes: 0