• Open Menu Close Menu
  • Apple
  • Shopping Bag
  • Apple
  • Mac
  • iPad
  • iPhone
  • Watch
  • TV
  • Music
  • Support
  • Search apple.com
  • Shopping Bag

Lists

Open Menu Close Menu
  • Terms and Conditions
  • Lists hosted on this site
  • Email the Postmaster
  • Tips for posting to public mailing lists
Re: Crash in KVO when using -keyPathsForValuesAffecting<Key>
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Crash in KVO when using -keyPathsForValuesAffecting<Key>


  • Subject: Re: Crash in KVO when using -keyPathsForValuesAffecting<Key>
  • From: Jeff Johnson <email@hidden>
  • Date: Sat, 20 Jun 2009 14:39:00 -0500

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 (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


  • Follow-Ups:
    • Re: Crash in KVO when using -keyPathsForValuesAffecting<Key>
      • From: Jean-Daniel Dupas <email@hidden>
    • Re: Crash in KVO when using -keyPathsForValuesAffecting<Key>
      • From: Clark Cox <email@hidden>
References: 
 >Crash in KVO when using -keyPathsForValuesAffecting<Key> (From: Jean-Daniel Dupas <email@hidden>)
 >Re: Crash in KVO when using -keyPathsForValuesAffecting<Key> (From: Jeff Johnson <email@hidden>)

  • Prev by Date: Re: Crash in KVO when using -keyPathsForValuesAffecting<Key>
  • Next by Date: Re: programmatically creating a NSMatrix with a prototype cell
  • Previous by thread: Re: Crash in KVO when using -keyPathsForValuesAffecting<Key>
  • Next by thread: Re: Crash in KVO when using -keyPathsForValuesAffecting<Key>
  • Index(es):
    • Date
    • Thread