Re: KVC and KVO for arrays
Re: KVC and KVO for arrays
- Subject: Re: KVC and KVO for arrays
- From: Adam P Jenkins <email@hidden>
- Date: Wed, 13 Feb 2008 14:24:02 -0500
On Feb 13, 2008, at 12:08 PM, Jens Alfke wrote:
On 13 Feb '08, at 8:51 AM, Adam P Jenkins wrote:
@implementation Palette
- (NSMutableArray*)kvoColors
{
return [self mutableArrayValueForKey:@"colors"];
}
@end
Now, I can write
[[palette kvoColors] addObject:[NSColor whiteColor]];
and observers of palette will be duly notified.
This has always confused me, and I never got it to work right when I
tried this technique. The weird part is that you have two KV
properties for the same array, with different semantics. Your trick
of declaring a "colors" ivar but no accessor methods looks like it
helps, but one thing still worries me:
If I made that addObject call, as in your example, what KVO
notifications does the Palette send? Is it the "kvoColors" or
"colors" property that's notified as being changed?
I'm afraid that it would be the latter, which makes me somewhat
afraid to use this technique, since I'd be too likely to get mixed
up and register for notifications of "kvoColors" instead of
"colors", and then spend hours trying to figure out why my listener
doesn't get called...
—Jens
The kvoColors method is not necessary, and you can leave it out if you
think it confuses things. I just added it for illustrative purposes.
By default, simply adding an instance variable is enough to create a
KVC and KVO compliant property, unless a subclass has overridden
accessInstanceVariablesDirectly to return FALSE. Here is a complete
and compilable program which demonstrates a Party class with an
attendees array property, and demonstrates an observer receiving
events about the array being modified in place, all without writing
any indexed accessors.
#import <Foundation/Foundation.h>
@interface Party : NSObject
{
// just adding this instance variable is enough to create a KVC and
KVO compliant
// attendees property
NSMutableArray *attendees;
}
- (void)printAttendeesAddress;
@end
@implementation Party
- (id)init {
[super init];
attendees = [NSMutableArray array];
return self;
}
- (void)printAttendeesAddress {
NSLog(@"Attendees array is at address %p", attendees);
}
@end
@interface MyObserver : NSObject
@end
@implementation MyObserver
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context
{
NSLog(@"Received notification: keyPath:%@ ofObject:%@ change:%@",
keyPath, object, change);
}
@end
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
Party *party = [Party new];
MyObserver *observer = [MyObserver new];
// observe attendees property
[party addObserver:observer
forKeyPath:@"attendees"
options:(NSKeyValueObservingOptionNew |
NSKeyValueObservingOptionOld)
context:NULL];
[party printAttendeesAddress];
// modifications to attendees will be logged by observer
NSMutableArray *attendees = [party
mutableArrayValueForKey:@"attendees"];
[attendees addObject:@"Joe Blow"];
[attendees addObject:@"Mary Jane"];
[attendees replaceObjectAtIndex:0 withObject:@"Spiderman"];
[attendees removeObjectAtIndex:1];
// this should print the same address as the previous invocation of
this method
// showing that the instance variable's underlying array isn't
getting copied
[party printAttendeesAddress];
[pool drain];
return 0;
}
_______________________________________________
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