I have many "model" objects whose properties are defined as "readonly" and shared among various components.
In some cases I need to create local mutable copies of the objects (using them for local mutable state)
I rather not implement NSMutableCopy protocol as the object should be immutable after it is created. The modified object could be "passed" around after copy+mutate operations.
Is there a suggested mechanism , or should I just implement a constructor receiving the "changed" parameters?
For example an object which parses a JSON to native types :
@interface ImmutableObject : NSObject
// various "readonly" properties
...
-(instancetype)initWithJSON:(NSDictionary *)jsonDictionary;
@property (nonatomic, readonly) MyClass1 *prop1;
@property (nonatomic, readonly) MyClass2 *prop2;
...
@property (nonatomic, readonly) NSArray<MyClass100 *> *prop100;
@end
@implementation
-(instancetype)initWithJSON:(NSDictionary *)jsonDictionary {
self = [super init];
[self parseDictionaryToNative:jsonDictionary];
return self;
}
@end
Somewhere in code:
ImmutableObject *mutated = [immutableObject mutableCopy]; // best way to accomplish this?
// change some values...
mutated.prop1 = ... // change the value to something new
self.state = [mutated copy]; // save the new object
@spinalwrap is correct, but in this case there is no reason to create the extra copy before storing it.
NSMutableArrayis a subclass ofNSArray, so can be used anywhere anNSArraycan be used (and this is very common). Same for yours. In your particular case, you'd probably do it this way:This is safe because you know that this block of code is the only block that has a reference to the mutable version of the object (because you created it here).
That said, once you've created a mutable subclass, you now need to consider the possibility that any
ImmutableObjectyou are passed might actually be aMutableObject, and so make defensive copies (just as is done withNSArray,NSString, etc.) For example:This is made fairly efficient by implementing
copyonImmutableObjectandreturn self, and implementingcopyonMutableObjectas an actual copy, usually like this:ImmutableObject.m
MutableObject.m
So the copy is almost free if the object was immutable already. I say "fairly efficient" because it still causes some unnecessary copies of mutable objects that are never mutated. Swift's copy-on-write system for value types was specifically created to deal with this problem in ObjC. But the above is the common pattern in ObjC.