On Apr 7, 2015, at 10:58 , Daryle Walker <[email protected]> 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 ([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]