On Apr 7, 2015, at 10:58 , Daryle Walker <dary...@mac.com> wrote:

> @interface MyClass : NSObject
> @property (readonly) NSArray *  myDatumList;
> @property NSArray *  myDataList;
> @end
> 
> @implementation MyClass
> 
> - (NSUInteger)countOfMyDatumList {
>    return self.myDataList.count;
> }
> 
> - (id)objectInMyDatumListAtIndex:(NSUInteger)index {
>    NSDictionary * const  dict = self.myDataList[index];
>    return dict[@“datum”];
> }
> @end

The problem is that this approach doesn’t actually work, not in this form. 
There’s a little bit of Doing It Wrong™, but mostly this is pretty badly broken 
in Cocoa.

Your custom accessors are *never* used, except in two circumstances:

1. If you expose them publicly, and a client of MyClass invokes them directly. 
This is fine, except that clients don’t get access via all the other NSArray 
methods for free.

2. Clients access the “myDatumList” property via a *proxy* object which is 
obtained as follows:

        [someMyClassInstance valueForKey: @“myDatumList”]

Using the returned proxy object as a NSArray, they can then use any of the 
standard NSArray methods (including ordinary ‘count’, ‘objectAtIndex:’ and all 
the others) on this proxy, and the calls will be translated into some 
combination of your custom accessors.

This is fine, too, except that you’ve lost the ability for clients of the class 
to write:

        myClassInstance.myDatumList.count

etc. It would *seem* you could solve this by giving MyClass a simple getter:

        - (NSArray*) myDatumList {
                return [self valueForKey: @“myDatumList”];
        }

but if you try that, you’ll find it causes an infinite loop. *By API contract* 
(look in NSKeyValueCoding.h for the gory details), under these circumstances 
‘valueForKey’ will call the ‘myDatumList’ method — hence the loop.

(In your case, without an implementation of the “myDatumList” getter, because 
you’ve declared a “myDatumList” property and declared it @dynamic, you’d just 
end up crashing, because ‘valueForKey’ would try to call a method that doesn’t 
exist. Or, if you let it be @synthesized, ‘valueForKey’ would call a method 
that always returns nil.)

There’s no direct solution to this. You either can’t use the custom NSArray 
accessors, or clients of the class have to remember to us the crummy 
‘valueForKey’ approach and you have to get rid of the “myDatumList” property. 
The indirect solution is to implement your own proxy object. It’s doable, and 
I’ve done it in the past, but it makes your head hurt.

My suggestion, therefore, is to take one of the following approaches:

— If clients of the class access “myDatumList” in limited ways, just expose the 
custom accessors directly, and don’t have the @property at all.

— Have the “myDataList” property be cleverer, and let it maintain a parallel 
array (_myDatumList). This is just an array, therefore, without custom 
accessors, so the “myDatumList” property will work fine.

Finally, if on top of all of this you want the “myDatumList” property to be KVO 
compliant — if you want to KVO observe it — there’s yet another level of 
complication because there’s a different proxy involved:

        [<self-or-someMyClassInstance > mutableArrayValueForKey: @“myDatumList”]

and/or you must provide KVO compliance manually when updating the backing store 
NSArrays. (And if you think this proxy avoids the looping problem of the 
non-mutable proxy — it doesn’t.)

Sorry to ruin your day. :)



_______________________________________________

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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 arch...@mail-archive.com

Reply via email to