【问题标题】:Crash when trying to remove KVO observer尝试删除 KVO 观察者时崩溃
【发布时间】:2017-04-29 00:57:32
【问题描述】:

我第一次实现了 KVO,在某些情况下,它正在工作,并且 observeValue 被正确调用。但是,我在尝试删除 deinit 中的观察者时遇到了崩溃:

无法移除观察者 为了 关键路径“downloadInProgress”来自 因为它没有注册为观察者。

...虽然我确实在viewDidLoad 中注册了对象。

// At the top of my file
dynamic var downloadInProgress: Bool = false


override func viewDidLoad() {
    super.viewDidLoad()
    self.addObserver(self, forKeyPath:  #keyPath(downloadInProgress), options: [.old,.new], context: nil)
}

deinit {
    // It crashes here
    removeObserver(self, forKeyPath: #keyPath(downloadInProgress))
}

基本上如果downloadInProgress = false,它会崩溃。我究竟做错了什么?谢谢。

【问题讨论】:

  • 你确定这个类总是被一个调用viewDidLoad()的路径实例化吗?

标签: swift swift3 key-value-observing


【解决方案1】:

你写的

// At the top of my file
dynamic var downloadInProgress: Bool = false

所以它不是对象的一部分?如果是这样,那可能是问题所在。 KeyValueObserving 是来自 ObjectiveC 的一种技术。在 Swift 中,它有一些限制。一个限制是它只适用于从 NSObject 派生的类。如果它是我期望的全局变量,则不满足。

Apple documentation:

你可以在 Swift 类中使用键值观察,只要该类继承自 NSObject 类

如果你有一个像这样的 kvo 对象,它应该可以工作:

final class MyObject: NSObject {
   dynamic var downloadInProgress: Bool = false
}

self.addObserver(self, forKeyPath:  #keyPath(myobjectinstance.downloadInProgress), options: [.old,.new], context: nil)

提示:以后尽量避免使用 KVO,因为它在 swift 中并不常见。

【讨论】:

  • 如果我不应该使用 KVO,它的替代品是什么?
  • 更多的是架构问题。一种解决方案可能是使用对象和装饰器模式。我在这里实现了一个例子:stackoverflow.com/questions/43644972/…
  • swift 中没有直接的等价物。注意:在 ObjectiveC 中使用也不是一个好主意。
  • Observer 是一种模式,一旦你理解了它,你就会在任何地方看到它的用途。间接性非常酷。您可以使用各种对象注册观察者,而不是连接这些对象以显式调用您。虽然这种间接方式是管理依赖关系的一种有用方式,但它很容易走极端。过度使用 Observer 往往会使系统非常难以理解和跟踪。 ~ Robert Martin,敏捷软件开发,第 24 章
  • 这只是我的意见。使用与否,您的选择。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-01
  • 2011-01-19
  • 1970-01-01
  • 1970-01-01
  • 2012-01-16
相关资源
最近更新 更多