Learning to be Giant.

Tricky stuff of NSMutableDictionary

|

I went into a quite tricky trouble caused by -setObject:forKey:.

I took use of MagicalRecord to manage my Core Data. However, when saving the context, the data cannot be persisted. An error log as following appeared:

NO CHANGES IN CONTEXT on *** BACKGROUND THREAD *** - NOT SAVING

And my codes look like following:

NSMutableDictionary *dict = entity.dict;
[dict setObject:obj_a forKey:@"task"];
[dict setObject:obj_b forKey:@"info"];
[[NSManagedObjectContext contextForCurrentThread] saveToPersistentStoreAndAwait];
obj_a and obj_b are two NSDictionarys.

When I changed the content of Obj_a and Obj_b, and then call the persist method, the above error occurs. After several careful checks, I found out that even before line.2, the op output of dict was still the latest(which is what I supposed it to be after line.3, that means line.2 and line.3 are useless). That made me realize the setObject:forKey: method will only save a pointer to the object instead of make a deep copy of that. And that explains why [NSManagedObjectContext hasChanges] always returns NO. Although the content of obj_a and obj_b were changed, its address remained unchanged. As the -hasChanges method took use of key-value-observing, it cannot find out what is going on in the child object. Therefore, the context will be regarded as unchanged.

I then refactored the codes to be like this:

NSMutableDictionary *dict = entity.dict;
[dict setObject:[obj_a copy] forKey:@"task"];
[dict setObject:[obj_b copy] forKey:@"info"];
[[NSManagedObjectContext contextForCurrentThread] saveToPersistentStoreAndAwait];

Problem solved.

Comments