views:

66

answers:

2

Say I'd like a mutable, unordered to-many relationship. For internal optimization reasons, it'd be best to store this in an NSMutableDictionary rather than an NSMutableSet. But I'd like to keep that implementation detail private.

I'd also like to provide some KVO-compliant accessors, so:

- (NSSet*)things;
- (NSUInteger)countOfThings;
- (void)addThings:(NSSet*)someThings;
- (void)removeThings:(NSSet*)someThings;

Now, it'd be convenient and less evil to provide accessors (private ones, of course, in my implementation file) for the dictionary as well, so:

@interface MYClassWithThings ()
@property (retain) NSMutableDictionary* keyedThings;
@end

This seems good to me! I can use accessors to mess with my keyedThings within the class, but other objects think they're dealing with a mutable, unordered (, unkeyed!) to-many relationship.

I'm concerned that several things I'm doing may be "evil" though, according to good style and Apple approval and whatnot. Have I done anything evil here? (For example, is it wrong not to provide setThings, since the things property is supposedly mutable?)

+2  A: 

Nothing evil here. The only mandatory mutation methods for an unordered relationship are addThings: and removeThings: (see the KVC doc). The accessors for your keyedThings property won't collide with any KVC accessor, so you're also fine there.

To put your mind at ease, the only things Apple's static analyzer is known to check for are messages to undocumented APIs. Other than that, if your implementation decisions don't affect the app's behavior, you're alright for App Store approval.

Update: I got interested in this question and re-read the KVC doc for myself. The language here gave me pause:

To-many unordered relationships are most often modeled using instance of NSSet or a subclass. In that case the key-value coding will, if it doesn’t find these accessor patterns for the property, directly access the set. Typically, you only implement these methods if you are using a custom collection class that needs to be accessed as if it was a set.

It sounds like the author would prefer that you get rid of things and implement enumeratorOfThings: and memberOfThings:.

Tom
There is no `things:`, since it doesn't take an argument. It's just `things`.
Peter Hosey
Yes, it does sound that way... I wonder why, though. Performance reasons, perhaps? Because it seems to me much cleaner to provide access to a set than to provide `enumeratorOfThings:` and `memberOfThings:`, since both of those could be obtained from the set.
andyvn22
andyvn22: Depending on how your dictionary is lain out, either or both of those methods could be more efficient ways of doing those tasks than obtaining a temporary set and doing them with that.
Peter Hosey
@Peter: Thanks. Edited.
Tom
+2  A: 

I wouldn't make a property (even a private one) for the dictionary, but I don't think there's anything wrong with it.

… is it wrong not to provide setThings, since the things property is supposedly mutable?

Yes. KVC will not like the absence of a setThings: method.

Peter Hosey