Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/cocoa/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 什么时候将自己作为密钥的观察者移除是非法的?_Ios_Cocoa_Key Value Observing - Fatal编程技术网

Ios 什么时候将自己作为密钥的观察者移除是非法的?

Ios 什么时候将自己作为密钥的观察者移除是非法的?,ios,cocoa,key-value-observing,Ios,Cocoa,Key Value Observing,我的应用程序遇到问题。为了方便起见,my app delegate更容易观察自己的属性。但是,当作为观察者删除应用程序委托时,我收到一个错误 我将其归结为一个小代码示例和结果(稍后显示) 我的问题是,什么时候删除自己作为自己密钥的观察者是非法的,在下面的示例中,典型的cocoa开发人员如何解决这个问题: 从这个代码 #import "AppDelegate.h" @interface Thing : NSObject @property (nonatomic, strong) Thing *

我的应用程序遇到问题。为了方便起见,my app delegate更容易观察自己的属性。但是,当作为观察者删除应用程序委托时,我收到一个错误

我将其归结为一个小代码示例和结果(稍后显示)

我的问题是,什么时候删除自己作为自己密钥的观察者是非法的,在下面的示例中,典型的cocoa开发人员如何解决这个问题:

从这个代码

#import "AppDelegate.h"

@interface Thing : NSObject
@property (nonatomic, strong) Thing * next;
@property (nonatomic, strong) id value;
@end

@implementation Thing
@synthesize next,value;
+(Thing*)thing
{
    return [[Thing new] autorelease];
}
@end

@interface AppDelegate ()
@property (strong, nonatomic) Thing * thing;
@end

@implementation AppDelegate

@synthesize window = _window, thing;

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

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
    // Insert code here to initialize your application

    Thing * thing2 = [Thing thing];
    thing2.value = @"hello";

    Thing * thing1 = [Thing thing];
    thing1.next = thing2;
    self.thing = thing1;

    [self addObserver:self forKeyPath:@"thing.next.value" options:0 context:NULL];
    [self addObserver:self forKeyPath:@"thing.next" options:0 context:NULL];

    Thing * thing3 = [Thing thing];
    thing3.value = @"goodbye";

    self.thing.next = thing3;
}

- (void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    NSLog(@"value did change for keyPath '%@'", keyPath);
    [self removeObserver:self forKeyPath:@"thing.next.value"];
    [self removeObserver:self forKeyPath:@"thing.next"];
}

@end
我得到这个结果

2011-11-03 13:32:02.123 TestKVO[11637:707]的值确实发生了变化 关键路径“下一个”

2011-11-03 13:32:02.124 TestKVO[11637:707]无法删除观察者 对于来自的键路径“next.value” ,很可能是因为键“next”的值 已更改,但未发送适当的KVO通知。检查 对象类的KVO遵从性

两件事:

1) 您正在实现自己的setter吗?如果是这样,您需要通过适当地发送
willChangeValueForKey:
didChangeValueForKey:
来确保它们符合KVO。在苹果的《关键价值观察编程指南》中查找有关KVO合规性的部分

编辑:上面的内容是为了让你检查你的班级的整体合规性@sam是正确的,您不需要在自定义setter中使用
willChange…
didChange…
,除非您禁用了自动通知


2) 与其让对象观察它自己的属性(IMHO有点奇怪),不如实现自定义设置器,在值更改时在对象中执行任何您想要的操作。

我认为问题在于,您注册了两个包含在内的通知源

相反,你应该:

  • 只注册
    @“thing.next”
  • 在通知处理方法中,在旧的
    @“thing.next.value”
    上注销
    @“thing.next.value”
    值(可在
    更改
    字典中找到),然后在新的
    @“thing.next.value”
    值(也可在
    更改
    字典中找到)上注册
    @“thing.next.value”

这样,当
@“thing.next”
键路径更改时,绑定保持一致。

我同意重写setter可能是更好的方法,但他不必调用
willChangeValueForKey:
/
didChangeValueForKey:
。事实上,如果他这样做了,他可能会让他的方法触发两次,因为kvo是自动的,除非你关闭它,即使你自己编写setter。请参阅和
automaticallynotifiesobsersforkey:
@sam关于自动KVO是正确的。我的意思是说我的评论是为了检查全班的合规性。我将编辑我的答案。这很可能是正确的。当您注册
thing.next.value
时,您的应用程序保留了对
thing.next
的弱引用(即未保留)。然后更改
thing.next
使KVO感到困惑,因为
thing.next
已更改,因此更改了
thing.next.value
但没有为
thing.next.value
更改发送KVO通知。呸。这可能会让人困惑。