Suppose that two objects A and B are observing a key on a third object C. Suppose further that from its observeValueForKeyPath method, A releases B, causing B's dealloc method to be called, and that B's dealloc method properly calls removeObserver. Then, despite the call to removeObserver, it looks like Cocoa tries to call observeValueForKeyPath on B anyway, which is a call off into empty space.

This is on 10.4.11.

1) Am I doing something wrong?
2) Is this documented somewhere? (I didn't find it anywhere)
3) If this is already known, is there a customary pattern for avoiding the problem? "Never release from observeValueForKeyPath" is a bit harsh!

Test code at end. To use, make MainMenu.nib instantiate the object 'test', and make a window with a checkbox bound to values.testkey on UserDefaultsController. Check the box. Here is the result if this is done with NSZombieEnabled=YES:

2008-05-29 14:57:23.148 testcase[8682] helper init
2008-05-29 14:57:25.869 testcase[8682] test observe
2008-05-29 14:57:25.869 testcase[8682] helper dealloc
2008-05-29 14:57:25.876 testcase[8682] *** -[_NSZombie forward::] not overridden!

thanks for any pointers,
Geoff

[snip]

#import <Cocoa/Cocoa.h>

/// interfaces

@interface helper : NSObject { }
@end

@interface test : NSObject {
  id obj;
}
@end

/// helper implementation

@implementation helper

- (id)init {
  [[NSUserDefaultsController sharedUserDefaultsController]
     addObserver:self
      forKeyPath:@"values.testkey"
         options:NSKeyValueObservingOptionNew
         context:NULL];
  NSLog(@"helper init");
  return [super init];
}

- (void)dealloc {
  [[NSUserDefaultsController sharedUserDefaultsController]
     removeObserver:self
         forKeyPath:@"values.testkey"];
  NSLog(@"helper dealloc");
  [super dealloc];
}

- (void)observeValueForKeyPath:(NSString *)keyPath
                      ofObject:(id)object
                        change:(NSDictionary *)change
                       context:(void *)context {
  NSLog(@"helper observe");
}

@end

/// test implementation

@implementation test

- (void)awakeFromNib {
  [[NSUserDefaultsController sharedUserDefaultsController]
     addObserver:self
      forKeyPath:@"values.testkey"
         options:NSKeyValueObservingOptionNew
         context:NULL];

  obj = [[helper alloc] init];
}

- (void)dealloc {
  NSLog(@"test dealloc");
  [[NSUserDefaultsController sharedUserDefaultsController]
     removeObserver:self
         forKeyPath:@"values.testkey"];
  [obj release];
  obj = nil;
  [super dealloc];
}

- (void)observeValueForKeyPath:(NSString *)keyPath
                      ofObject:(id)object
                        change:(NSDictionary *)change
                       context:(void *)context {
  NSLog(@"test observe");
  [obj release];
  obj = nil;
}

@end
// (end of file)
_______________________________________________

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 [EMAIL PROTECTED]

Reply via email to