On Jul 10, 2012, at 23:17 , Rick Mann wrote:

> Is this possible? My first thought is to make a read-only NSArray* property, 
> but then it seems that addition or removal of elements to/from that property 
> wouldn't get observed; i.e., an NSArray should never change its contents.

No, your first thought was correct.

It's not really an "array" property, it's an indexed to-many property**. As far 
as the client is concerned the value returned by the property could be (and 
sometimes is***) a proxy that doesn't permit the underlying NSMutableArray ivar 
(assuming there is on) to be mutated. Property type NSArray* is just an 
abstract behavior of the returned object. (Remember that NSArray isn't a 
concrete class.)

All that's required is that the indexed to-many property be mutated (by objects 
which *are* allowed to mutate it) in a KVO-compliant manner****. In that case, 
observers of the property will be notified.


** It's possible, though perhaps less usual, for a NSArray* property to be a 
to-one property with an array value. Semantically, it's a different kind of 
property (an attribute rather than a relationship), but there's no syntactic 
difference. Warning: The distinction can cause your brain to hurt.

*** Here's how you get a immutable proxy to an indexed to-one property:

a. Implement the countOf<Key> and objectIn<Key>AtIndex: methods in the class 
with the property.

b. Have clients of the class invoke 'valueForKey: @"<key>"' on an instance of 
the class with the property.

c. DO NOT implement a getter for the property "<key>". Doing so will cause 
infinite recursion when it's accessed. (This is one of KVC's most annoying 
defects.)

**** There isn't AFAIK a really easy way to prevent clients that aren't 
supposed to mutate the property from just invoking 'mutableArrayValueForKey: 
@"<key>"' by themselves.

One alternative approach is to use *two* property names: <privateKey> and 
<publicKey>.

You can then have <publicKey>'s getter return '[self valueForKey: 
@"privateKey"]'. That solves the infinitely-recursing-getter problem, but still 
returns an immutable observable proxy.

You can then also implement the custom add/remove KVC accessors for <publicKey> 
to throw an exception. Objects that *are* permitted to mutate the array will 
therefore need to know privateKey. (Likely, only instances of the implementing 
class are the only ones allow, so they know privateKey anyway.)

A second alternative approach is write your own mutable and immutable array 
proxies (subclasses of NSArray) instead of using the ones provided by KVC. It 
isn't terribly hard.

A third alternative approach is simply to trust your class's clients to respect 
the mutability rules of your class API. :)


_______________________________________________

Cocoa-dev mailing list ([email protected])

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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to [email protected]

Reply via email to