So I had a vanilla Core Data entity with a
@property (nonatomic, retain) NSString *text property and a
NSTextView *textView used to edit text that would be stored to this value. Initialization looked something like
textView.string = model.text and saving looks like
model.text = textView.string in textDidEndEditing:.
All good right? Wrong. The value wasn’t sticking. It was changed even though the model’s setter without ever being called. Can you guess why?
It took me wayy too long to debug, but finally… checking out NSText’s string getter method, we see:
For performance reasons, this method returns the current backing store of the text object. If you want to maintain a snapshot of this as you manipulate the text storage, you should make a copy of the appropriate substring.
NSLog(@"%@", [textView.string class]) we see it is actually an instance of NSBigMutableString. This means both the text editor and entity now hold a reference to the same mutable NSString. Basic CS101, duh! There are two possible fixes: Define the string property using copy vs retain,
@property (nonatomic, copy) NSString *text or manually copy the string when setting the value like
model.text = [textView.string copy]. See this Stack Overflow post for more info on when to use retain/copy on NSString.