I recently got into a minor (but not unfriendly) disagreement in the comments on this question about how best to implement a read-only, immutable array property with underlying mutable storage in Objective-C. (The comments have since been moved to chat.)
First, let me be clear about what I want.
- I want a property that is read-only, i.e., it is not assignable.
myObject.array = anotherArray
should fail. - I want the type of that property to be immutable so that new elements cannot be added to it through the property itself. Clearly, this means the type of the property should be
NSArray
. - I want the storage (i.e., the ivar) for that property to be mutable, because I will provide methods on the containing class to mutate it.
Since it seems not to be clear to some, let me stress that this question is about the frogs
property of FrogBox
class below, nothing more and nothing less.
I'll use the same contrived example from the linked question, a box of frogs, called FrogBox
:
@interface FrogBox : NSObject
@property (nonatomic, readonly) NSArray *frogs;
- (void)addFrog:(Frog*)frog;
- (void)removeFrog:(Frog*)frog;
@end
@implementation FrogBox {
NSMutableArray *_frogs;
}
@dynamic frogs;
- (instancetype)init {
self = [super init];
if (self) {
_frogs = [NSMutableArray array];
}
return self;
}
- (NSArray*)frogs {
return _frogs;
}
- (void)addFrog:(Frog*)frog {
[_frogs addObject:frog];
}
- (void)removeFrog:(Frog*)frog {
// Frog implements isEqual and hash.
[_frogs removeObject:frog];
}
@end
Now, let's get something out of the way. The @dynamic
directive is not strictly necessary here. Using @dynamic
suppresses automatic synthesis of an ivar for the frogs
property. Of course, if automatic synthesis sees an ivar with the same name as what it would have created, it just uses the supplied one. So why do I use it? I think it adds clarity and signals intent. If you don't like it, just imagine it's not there. It's not germane to the question.
The question is not about whether it's a good idea to want a publicly readonly, immutable and privately mutable property or not. It's about whether this is the most efficient way (in terms of syntax and clock cycles) to achieve that goal. I believe that it is, but I'd like to hear from the community, and am perfectly open to having my mind changed.