Re: Redeclaring property types in mutable subclasses
Re: Redeclaring property types in mutable subclasses
- Subject: Re: Redeclaring property types in mutable subclasses
- From: Ken Thomases <email@hidden>
- Date: Tue, 29 Mar 2011 00:54:03 -0500
On Mar 28, 2011, at 11:28 PM, Quincey Morris wrote:
> On Mar 28, 2011, at 20:05, Adam Ernst wrote:
>
>> I have a class with an array property:
>>
>> @interface Widget : NSObject {}
>> @property (retain, readonly) NSArray *gizmos;
>> @end
>>
>> I make a mutable subclass. In addition to making the array property readwrite, I also make it an NSMutableArray for convenience:
>>
>> @interface MutableWidget : Widget {}
>> @property (retain, readwrite) NSMutableArray *gizmos;
>> @end
>>
>> This triggers a warning:
>>
>> Property 'gizmos' type does not match super class 'Widget' property type
>>
>> I can understand why this is being triggered. How can I work around it? I could keep it a straight NSArray, but this is cumbersome to edit. Suggestions on how to properly model this in my code?
>
> The pattern I use is:
>
>> @interface MutableWidget : Widget {}
>> @property (retain, readwrite) NSMutableArray *mutableGizmos;
>> @end
Do either of you really mean for that property to be read-write?
I can see making a property read-write with an immutable type, and I can see (although I don't particularly like) making a read-only property return a mutable type. (Having properties of mutable type breaks encapsulation in a big way.) But it seems strange to me to make a read-write property of mutable type.
Especially you, Quincey, when you've made a "sibling", mutable variant of the property. Is there really a setMutableGizmos: method? What does it mean?
Also, if you're using -mutableArrayValueForKey: without providing the mutation accessors, then that's probably asking for grief. Actually, you said something I didn't follow about a setter for the gizmos property, but that's read-only. So, it's not clear to me how the proxy is supposed to mutate it (other than KVC's direct instance variable access, which I always disable). And without either a proper setter or the mutation accessors, you've violated encapsulation. Clients of your class can mutate your property without you being informed (unless you KVObserve your own property).
Here's what makes sense to me:
@interface Widget : NSObject {}
@property (retain, readonly) NSArray *gizmos;
// optionally, any of:
- (NSUInteger) countOfGizmos;
- (id) objectInGizmosAtIndex:(NSUInteger)index;
- (NSArray*) gizmosAtIndexes:(NSIndexSet*)indexes;
- (void) getGizmos:(Gizmo**)buffer range:(NSRange)inRange;
@end
@interface MutableWidget : Widget {}
// At least one of:
- (void) insertObject:(Gizmo*)gizmo inGizmosAtIndex:(NSUInteger)index;
- (void) insertGizmos:(NSArray *)gizmoArray atIndexes:(NSIndexSet *)indexes;
// At least one of:
- (void) removeObjectFromGizmosAtIndex:(NSUInteger)index;
- (void) removeGizmosAtIndexes:(NSIndexSet *)indexes;
// optionally, either of:
- (void) replaceObjectInGizmosAtIndex:(NSUInteger)index withObject:(id)anObject;
- (void) replaceGizmosAtIndexes:(NSIndexSet *)indexes withGizmos:(NSArray *)gizmoArray;
@end
Then, clients of MutableWidget can either directly use those mutation accessors or they can invoke [aMutableWidget mutableArrayValueForKey:@"gizmos"] and mutate that. If you really want to wrap the latter in a convenience method, you can, but I don't think that constitutes a read-write property.
And I reiterate that one should almost always implement +(BOOL)accessInstanceVariablesDirectly { return NO; } on all one's classes.
If you're looking for guidance, I suggest contemplating what the framework classes do. Can you think of any mutable class which changes the type of one of the base class's properties to be mutable? Can you think of any which added a mutable variant of one of the base class's properties (as mutableGizmos is to gizmos)? Well, frankly, can you think of any framework class that has a property of mutable type?!?
No. Mutable subclasses should provide setters or mutation accessors. That's the core of what they should add to the interface of the immutable super class.
Regards,
Ken
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden