【发布时间】:2017-04-06 19:38:22
【问题描述】:
在这个简单的代码(Xcode 8.3)中,我创建了一个 Operation 子类实例,注册其isFinished 属性的 KVO 观察,并通过将其添加到我的队列来启动该操作:
class MyOperation : Operation {
override func main() {
print("starting")
print("finishing")
}
}
class ViewController: UIViewController {
let q = OperationQueue()
override func viewDidLoad() {
super.viewDidLoad()
let op = MyOperation()
op.addObserver(self, forKeyPath: #keyPath(MyOperation.isFinished), options: [], context: nil)
self.q.addOperation(op)
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
print("Observed \(keyPath)")
if let op = object as? Operation {
op.removeObserver(self, forKeyPath: #keyPath(MyOperation.isFinished))
}
}
}
如您所见,当然,我有一个observeValue(forKeyPath... 的实现,我的计划是在那里调用removeObserver(forKeyPath...。
问题是我的应用程序崩溃并显示“MyOperation 已解除分配,而键值观察者仍向其注册”。我们打印“开始”和“结束”,但我们从不打印“已观察”;该操作不存在在我收到我的 KVO 通知之前。
这似乎是第 22 条规则。如果我不能通过观察isFinished 来移除观察者,我应该什么时候做呢? [我可以通过将我在main 末尾设置的我自己的 KVO 可观察属性添加到 MyOperation 来解决这个问题。但是我必须这样做的想法很奇怪。这不正是为什么isFinished 是可观察的,所以我可以在这里做我想做的事吗?]
【问题讨论】:
-
会不会是developer.apple.com/library/content/technotes/tn2109/…提到的问题? – “当您使用键值观察 (KVO) 来观察 NSOperation 的 isFinished 属性时,可能会出现类似的问题。虽然 KVO 不保留观察者或被观察者,但仍有可能,即使您在您的-viewWillDisappear: 方法,KVO 通知可能已经为您的对象发送。如果发生这种情况,运行通知的线程最终可能会调用一个已释放的对象!"
-
@MartinR 注释的那部分讨论了
self(观察者)可能不存在的危险,因此可能会将KVO 通知发送到不存在的对象。这与我的问题相反;我的问题是操作(观察者)在没有向我发送我的 KVO 通知的情况下将不复存在。self是根视图控制器,无处可去。 -
有什么用处可以提一下,我试过了,我可以看到:
starting finishing Observed Optional("isFinished")?我的应用不会崩溃。我用的是xcode 8.2,希望能明白是怎么回事…… -
@AhmadF 如果您在 Xcode 8.2 中看到该结果并且没有崩溃,则表明这可能是(令人难以置信的)Xcode 8.3 中的一个新错误。我将在我的另一台机器(仍然有 Xcode 8.2)上尝试它,看看我是否可以确认。我会让你知道我发现了什么。谢谢!
-
@AhmadF 你说得对。我邀请您输入您在 Xcode 8.2 中尝试过并且所有三个
print语句都打印并且我们不会崩溃的事实作为答案,并暗示这可能是 Xcode 中的错误(或至少是新行为) 8.3.我会接受这个答案。非常感谢! (我还将向 Apple 提交错误报告。)
标签: swift key-value-observing nsoperation