Sorry, scratch that, I apparently misread your example. As Phil would say, I'm an idiot.

Does +keyPathsForValuesAffecting... actually support true keypaths? The documentation is unclear.

-Jeff


On Jun 20, 2009, at 1:45 PM, Jeff Johnson wrote:

When you implement + (NSSet *)keyPathsForValuesAffectingName { return [NSSet setWithObject:@"object.name"]; }, you're implicitly setting up KVO, so whenever the name of the MyObject instance changes, KVO notifications are sent for the name of the MyWrapper instance. When you manually call addObserver: and removeObserver: for exactly the same instances and keypaths, it's redundant and probably messes with the automatic KVO.

-Jeff


On Jun 20, 2009, at 1:08 PM, Jean-Daniel Dupas wrote:

Hello,

I'm experiencing some difficulties with KVO and auto dependent keys. Am I doing something wrong, or should I fill a bug report ?

Here is a test case.

MyObject is a class with a single property: name.
MyWrapper is a class that wrap a MyObject instance. It also declares a property 'name' which is defined as dependent of "object.name" (using +keyPathsForValuesAffectingName).

I'm creating 2 distinct wrappers that use the same underlying object.

I start to observe both wrapper's name.

Now, I want to destroy the first wrapper. I unregister observer and release it. Then, when I change the underlying object's name, the KVO machinery try to notify the released object instead of notifying the registred one (Note that NSZombieEnabled is set to YES).

2009-06-20 20:02:35.437 kvo[20984:807] wrapper 1: <MyWrapper: 0x104f10> 2009-06-20 20:02:35.439 kvo[20984:807] wrapper 2: <MyWrapper: 0x104f90> 2009-06-20 20:02:35.440 kvo[20984:807] add observer <Foo: 0x105f60> to wrapper <MyWrapper: 0x104f10> 2009-06-20 20:02:35.442 kvo[20984:807] add observer <Foo: 0x105f60> to wrapper <MyWrapper: 0x104f90> 2009-06-20 20:02:35.443 kvo[20984:807] remove observer <Foo: 0x105f60> to wrapper <MyWrapper: 0x104f10> 2009-06-20 20:02:35.444 kvo[20984:807] *** -[MyWrapper willChangeValueForKey:]: message sent to deallocated instance 0x104f10

----------- kvo-test.m ----------

#import <Foundation/Foundation.h>
#import <Foundation/NSDebug.h>

// Simple Object Class with a simple property
@interface MyObject : NSObject {
@private
NSString *_name;
}

@property(copy) NSString *name;

@end

@implementation MyObject

@synthesize name = _name;

- (void)dealloc {
[_name release];
[super dealloc];
}

@end

// Simple obejct wrapper with a name property that forward the underlyng object name
@interface MyWrapper : NSObject {
@private
MyObject *_object;
}

@property(copy) NSString *name;
@property(retain) MyObject *object;

@end

@implementation MyWrapper

@synthesize object = _object;

- (void)dealloc {
[_object release];
[super dealloc];
}

- (NSString *)name { return [_object name]; }
- (void)setName:(NSString *)aName { [_object setName:aName]; }

+ (NSSet *)keyPathsForValuesAffectingName { return [NSSet setWithObject:@"object.name"]; }

@end

// Observer class
@interface Foo : NSObject { }

@end

@implementation Foo

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject: (id)object change:(NSDictionary *)change context:(void *)context {
if (context == [Foo class]) {
  NSLog(@"name did change");
} else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}

@end


int main(int argc, char *argv[]) {
NSZombieEnabled = YES;

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

MyObject *obj = [[MyObject alloc] init];
obj.name = @"Hello KVO";

MyWrapper *w1 = [[MyWrapper alloc] init];
NSLog(@"wrapper 1: %@", w1);
w1.object = obj;

MyWrapper *w2 = [[MyWrapper alloc] init];
NSLog(@"wrapper 2: %@", w2);
w2.object = obj;

Foo *foo = [[Foo alloc] init];
NSLog(@"add observer %@ to wrapper %@", foo, w1);
[w1 addObserver:foo forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:[Foo class]];

NSLog(@"add observer %@ to wrapper %@", foo, w2);
[w2 addObserver:foo forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:[Foo class]];

NSLog(@"remove observer %@ to wrapper %@", foo, w1);
[w1 removeObserver:foo forKeyPath:@"name"];
[w1 release];

obj.name = @"Youpi";

[pool drain];
return 0;
}

_______________________________________________

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

This email sent to arch...@mail-archive.com

Reply via email to