Re: noob questions regarding KVC accessors for a mutable array property
Re: noob questions regarding KVC accessors for a mutable array property
- Subject: Re: noob questions regarding KVC accessors for a mutable array property
- From: Ken Thomases <email@hidden>
- Date: Thu, 26 Jun 2008 23:49:13 -0500
On Jun 26, 2008, at 6:54 PM, Stuart Malin wrote:
I am trying to gain a working understanding of KVC. I have made a
small app that has a class Party which has a property "attendees"
that holds Person objects. The attendees property is KVC compliant
for a mutable array (it has index accessors). In another part of my
app, I want to find the Nth attendee. My first approach to doing so
was to code:
Person *person = [[party mutableArrayValueForKey:@"attendees"]
objectAtIndex:index];
This does work, and, as I best understand, it complies with the KVC
protocol.
But I do believe this approach generates a proxy mutable array,
which seems inefficient to me.
Since you say below that you have an -attendees method, why not
Person *person = [[party attendees] objectAtIndex:index];
?
As the underlying Party class is KVC compliant for the attendees
property, I substituted the above with:
Person *person = [party objectInAttendeesAtIndex:index];
This does work. But I sense I may be breaking some sort of
"encapsulation" regarding the workings of KVC by using the accessors
that support it.
Doesn't seem like breaking encapsulation to me. Your code is still
always the gatekeeper of access to the property, so it's still
encapsulated. Just as much as it is to provide an -attendees method,
for example. In theory, it offers greater encapsulation since your
code could, if you wanted, make decisions about how to behave on an
element-by-element basis, which isn't possible if you give up the
array all at once.
The compiler issued a warning that "Party" may not respond to -
objectInAttendeesAtIndex: because I hadn't included the index
accessors in the class's header file... Which I could do.... But
then wonder even more if I am exposing something that I shouldn't.
Question: is it acceptable (perhaps even desirable) to expose the
index accessors of a class via its interface declaration (header
file)?
Yes.
I've said this before -- so much so that I probably sound like a
broken record: the property is not the ivar. The ivar, if it exists
at all, is an implementation detail for the property. The property is
the set of methods in the class interface which allow clients to
inquire about that information/state of your object. Therefore, it is
perfectly sensible, and often very much the right thing to do, to put
the KVC accessors in the interface of your class.
One example is when your to-many property is not backed by an array.
Suppose the objects in the to-many relationship are pulled from a
database. Or generated on demand, or whatever. Maybe your property
is backed by a library which only provides an interface for counting
and access-by-index (e.g. CGImageSource). Maybe your property
represents a large but sparse array. A property might not actually
have a -<key> accessor (because it would be prohibitively expensive to
generate the required array); it might _only_ exist as the set of
indexed accessors. In that case, as you can imagine, clients could
only use those KVC accessors to access the property, and they'd be
perfectly "right" to do so.
Also: I could add a method to my Party class to provide such access
in a way that seems more semantically direct, to wit: -personAtIndex:
Would providing such a method be preferred to having code elsewhere
in the app use the Party class's KVC index accessor(s)?
(It does seem quite redundant)
It seems redundant to me, too. (To be pedantic, it would more
appropriately be -attendeeAtIndex:. ;)
Seems like a matter of personal taste/style. Give it a try and see if
it feels more (or less) comfortable or efficient or whatever-criterion-
matters-to-you. I doubt you'll be excoriated here for either choice.
Separately, I have an accessor -attendees: of the Party class, which
is currently implemented as:
- (NSArray*) attendees
{
return [NSArray arrayWithArray:attendees]; // "attendees" is an
NSMutableArray, and is an ivar
}
I intentionally do not return the underlying mutable array, because
I don't want other code accessing the content without going through
the accessors.
Is my implementation reasonable? Or are there preferable ways to do
this (such as to return a copy of the mutable array)?
My personal theory is that using -copy (plus -autorelease) at least
gives the opportunity for a more efficient implementation. In this
case, there's probably no point, but in the general case my rule is to
go with the most semantically specific operation to give the
implementation the greatest amount of information and thus the
greatest opportunity to do something "smart".
That said, the larger issue is whether to protect yourself against
your clients. We just had a fairly good thread on this subject: <http://lists.apple.com/archives/Cocoa-dev/2008/Jun/msg00188.html
>.
Lastly, just let me say you're doing very well for a self-described
"noob"! :)
Cheers,
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