问题
I am reading "Core Data Programming Guide". It contains this text:
You must, however, change attribute values in a KVC-compliant fashion. For example, the following typically represents a programming error:
NSMutableString *mutableString = [NSMutableString stringWithString:@"Stig"];
[newEmployee setFirstName:mutableString];
[mutableString setString:@"Laura"];
For mutable values, you should either transfer ownership of the value to Core Data, or implement custom accessor methods to always perform a copy. The previous example may not represent an error if the class representing the Employee entity declared the firstName property (copy) (or implemented a custom setFirstName: method that copied the new value). In this case, after the invocation of setString: (in the third code line) the value of firstName would then still be “Stig” and not “Laura”.
Question regarding text: "In this case" is which case--the one where property is declared as "copy" or when its not?
Question regarding copy and programming practice: From what I have read here: NSString property: copy or retain? I understand
- that using copy will ensure that firstName is "Stig", not Laura
- it is wise to do so because "in almost all cases you want to prevent mutating an object's attributes behind its back"
I would really like to know what is the above quoted text trying to tell us in the context of Core Data. We have to use "copy" anyway whether using Core Data or not. Also, I would be glad if someone could throw more light on point "2" (it is wise to...) above as in what will be the consequences of mutating an object's attributes behind its back?
回答1:
your "Question regarding text: "In this case" is which case--the one where property is declared as "copy" or when its not?" mis-matched the point that Apple document wants to explain, I believe.
As Apple document points out, if custom-accessor-method is implemented normally, the default implementation does NOT copy attribute values. If the attribute value may be mutable and implements the NSCopying protocol (as is the case with NSString, for example), you can copy the value in a custom accessor to help preserve encapsulation (for example, in the case where an instance of NSMutableString is passed as a value).
Here is a copying setter snippet
@interface Department : NSManagedObject
{
}
@property(nonatomic, copy) NSString *name;
@end
@implementation Department
@dynamic name;
- (void)setName:(NSString *)newName
{
[self willChangeValueForKey:@"name"];
// NSString implements NSCopying, so copy the attribute value
NSString *newNameCopy = [newName copy];
[self setPrimitiveName:newNameCopy];
[self didChangeValueForKey:@"name"];
} @end
回答2:
The issue is when to use (and how) immutable values.
Since core data use KVO heavily when detecting changes done to objects, if you use a mutable property that is changed directly through it object and not through the property, CoreData will not detect the change to the object and your changes might not persist to the store.
If you use mutable NSManagedObject attributes, override the setter/getter method and use only them to mutate the underlying object (this mean that you are responsible to let CoreData know that a change did happen to the object, and it must be persisted to the store.
Also, if you use transformable properties for complex objects, you must trigger the change notifications yourself in order for CoreData to realise that a change has occurred, and the object should be re-transformed and saved when the context saves.
I would highly recommend that when it comes to simple objects like strings, you use immutable property values which will force you to go through the object properties and trigger the default KVO notification (copy attributes will also force the KVO notifications).
来源:https://stackoverflow.com/questions/15978563/implementing-custom-accessor-methods