KVO 和 ARC 如何移除Observer

Posted

技术标签:

【中文标题】KVO 和 ARC 如何移除Observer【英文标题】:KVO and ARC how to removeObserver 【发布时间】:2011-10-21 01:17:57 【问题描述】:

如何从ARC 下的对象中删除观察者?我们是否只是添加观察者而忘记删除它?如果我们不再手动管理内存,我们该从哪里放弃观察?

例如,在视图控制器上:

[self.view addObserver:self
            forKeyPath:@"self.frame"
               options:NSKeyValueObservingOptionNew 
               context:nil];

以前,我会在视图控制器的dealloc 方法中调用removeObserver:

【问题讨论】:

请注意,对 KVO .frame 来说这是一个非常糟糕的主意。正如 Apple 工程师在 *** 上在其他地方所写的那样,UIKit 的 frame 属性不符合 KVO。当它起作用时,它只是纯属偶然。 您的 keyPath 不应该是 @"frame" 而不是 @"self.frame" 【参考方案1】:

您仍然可以在 ARC 下实现-dealloc,这似乎是删除键值观察的合适位置。您只是不再在此方法中调用[super dealloc]

如果您之前覆盖了-release,那么您的做法是错误的。

【讨论】:

你确定吗?我引用clang.llvm.org/docs/…,第 7.1.2 节。 dealloc:“基本原理:即使 ARC 自动销毁实例变量,仍然有正当理由编写 dealloc 方法,例如释放不可保留的资源。在这种方法中调用 [super dealloc] 失败几乎总是一个错误。” @ElisevanLooij 是的,这是真的。如果你从这个类派生,很明显你必须调用[super dealloc]。还有谁应该为你做这件事。 @ElisevanLooij 糟糕,之前应该检查过。不允许在 dealloc 方法中调用[super dealloc]。不知道在子类化提到的类时这将如何工作。也许建议改用finalize(你打电话给[super finalize] @ElisevanLooij - 他们试图说明的重点是手动内存管理案例。因为在该方法中不最后调用[super dealloc] 几乎总是手动内存管理下的错误,编译器现在为您处理它,这就是您不能再直接调用-dealloc 的原因。您在 ARC 下的 -dealloc 方法中放入的唯一内容是您需要释放的任何非对象资源,或清理任务(如删除观察者)。他们使用的措辞有点含糊,但这就是他们的意思。 @BjörnMilcke - 当我评论 Elise 的回答时,-finalize 用于垃圾收集下,其中-dealloc 从未被调用,但将此代码放在-dealloc 下是完全可以接受的弧。 [super dealloc] 会自动为您调用,这就是为什么在 ARC 下调用它是错误的。【参考方案2】:

我用这段代码来做

- (void)dealloc

@try
    [self.uAvatarImage removeObserver:self forKeyPath:@"image" context:nil];
 @catch(id anException) 
    //do nothing, obviously it wasn't attached because an exception was thrown

    

【讨论】:

dealloc 中的异常处理有什么意义?对此采取任何行动都为时已晚。 在 dealloc 中删除实例变量上的观察者有什么意义?这个 uAvatarImage 很快就会连同它订阅了它的关键路径的所有观察者一起被释放。 @shoumikhin 我正在使用 ARC,我不得不在 dealloc 方法中删除观察者。我和你有同样的问题。但是,当我运行该类的多个实例时,最终我得到了 exc_bad_address 错误。这样做解决了这个问题。另外,来自***.com/questions/32490808/… 的答案帮助我发现了问题。【参考方案3】:

Elsewhere 在堆栈溢出时,Chris Hanson 建议为此使用 finalize 方法并实现一个单独的 invalidate 方法,以便所有者可以告诉对象它们已完成。过去我发现 Hanson 的解决方案是经过深思熟虑的,所以我会继续这样做。

【讨论】:

请注意,他指的是那里的垃圾收集,而不是 ARC(他的答案写于 2008 年)。在垃圾回收下,-dealloc 永远不会被调用。在 ARC 中,它是。在-dealloc 中删除 KVO 观察者是完全可以接受的,正如 Chris Lattner(他知道他在说什么)在 Apple 的开发者论坛中指出的那样:devforums.apple.com/message/475850 感谢布拉德,感谢您完成所有这些工作。不最终确定,是的释放,但没有[超级释放]。真的很简单,一旦你知道了。嘿,@drunknbass,接受那个人的回答!

以上是关于KVO 和 ARC 如何移除Observer的主要内容,如果未能解决你的问题,请参考以下文章

iOS 自动移除KVO观察者

IOS KVO没有在delloc中移除导致奔溃

核心数据预取和 KVO 合规性

移除对象时内存未释放 - 不清楚在 ARC 中释放的正确方法

iOS开发底层之KVO探索上 - 17

iOS开发底层之KVO探索上 - 17