【问题标题】:Swift 4 approach for observeValue(forKeyPath:...)observeValue(forKeyPath:...) 的 Swift 4 方法
【发布时间】:2018-05-13 18:19:51
【问题描述】:

我一直在努力寻找一个例子,但我所看到的在我的情况下不起作用。

下面的代码相当于什么:

object.addObserver(self, forKeyPath: "keyPath", options: [.new], context: nil)

override public func observeValue(
    forKeyPath keyPath: String?,
    of object: Any?, 
    change: [NSKeyValueChangeKey : Any]?, 
    context: UnsafeMutableRawPointer?) {

}

上面的代码有效,但我收到了来自 SwiftLink 的警告:

在使用 Swift 3.2 或更高版本时,更喜欢带有键路径的新基于块的 KVO API。

如果您能指出正确的方向,我将不胜感激。

【问题讨论】:

标签: swift swift4 key-value-observing keypaths


【解决方案1】:

Swift 4 引入了一系列具体的 Key-Path types、一个新的 Key-Path Expression 来生成它们,以及一个新的基于闭包的 observe 函数,可用于继承 NSObject 的类。

使用这组新功能,您的特定示例现在可以更简洁地表达:

self.observation = object.observe(\.keyPath) { 
    [unowned self] object, change in
    self.someFunction()
}

涉及的类型

Key-Path 语法

Key-Path 表达式的一般grammar 遵循\Type.keyPath 的形式,其中Type 是具体类型名称(包括任何泛型参数),keyPath 是一个或多个属性、下标的链,或可选的链接/强制展开后缀。另外,如果keyPath的Type可以从context中推断出来,那么可以省略,从而得到一个最精炼的\.keyPath

这些都是有效的键路径表达式:

\SomeStruct.someValue
\.someClassProperty
\.someInstance.someInnerProperty
\[Int].[1]
\[String].first?.count
\[SomeHashable: [Int]].["aStringLiteral, literally"]!.count.bitWidth

所有权

您是observe 函数返回的NSKeyValueObservation 实例的所有者,这意味着,您不必 addObserverremoveObserver 了;相反,只要你需要观察观察,你就会一直强烈地引用它。

您也不需要invalidate():它会优雅地deinit。因此,您可以让它一直存活到持有它的实例死亡,也可以通过 niling 引用手动停止它,或者如果您出于某种臭名昭著的原因需要保持实例存活,甚至可以调用 invalidate()

注意事项

您可能已经注意到,观察仍然潜伏在 Cocoa 的 KVO 机制的范围内,因此它仅适用于 Obj-C 类和继承 NSObject 的 Swift 类(每个 Swift-dev 最喜欢的类型),并附加要求任何您打算观察的值,必须标记为@objc(每个 Swift 开发人员最喜欢的属性)并声明为dynamic

话虽如此,整体机制是一个值得欢迎的改进,特别是因为它设法 Swiftify 从我们可能碰巧需要使用的模块(例如Foundation)中观察导入的NSObjects,并且不会冒削弱表达能力的风险我们非常努力地在每次按键时获得力量。

附带说明,Key-Path String Expressions 仍然需要 dynamically access NSObject 的属性到 KVC 或调用 value(forKey(Path):)

KVO 之外

Key-Path Expressions 比 KVO 更多。 \Type.path 表达式可以存储为 KeyPath 对象以供以后重用。它们有可写、部分和类型擦除的味道。它们可以增强为合成而设计的 getter/setter 函数的表达能力,更不用说它们在让那些最有胆量的人深入研究 Lenses 和 Prisms 等功能概念世界中所起的作用。我建议您查看下面的链接,详细了解他们可以打开的许多开发门。

链接:

Key-Path Expression @ docs.swift.org

KVO docs @ Apple

Swift Evolution Smart KeyPaths proposal

Ole Begemann's Whats-new-in-Swift-4 playground with Key-Path examples

WWDC 2017 Video: What's New in FoundationSKP 为 4:35,KVO 为 19:40。

【讨论】:

  • 你能告诉我在哪里可以找到你在“所有权”部分所说的话吗?我正在参考文献中寻找它,但我没有看到它。
  • @dava 据我所知,最接近官方明确提及的是invalidateobserve 的文档字符串。两者都将按预期显示在 Xcode 的快速帮助中。我还为此添加了一个 WWDC 视频并扩展了所有权部分。
  • 很好的答案!谢谢!
【解决方案2】:

当我在 iOS 10 中使用此方法时遇到应用程序崩溃时,添加一些内容。

在 iOS 10 中,您仍然需要在释放类之前删除观察者,否则您将收到崩溃 NSInternalInconsistencyException 声明:

C 的实例A 已被释放,而键值观察者仍向其注册。

为了避免这种崩溃。只需将您正在使用的观察者属性设置为nil

deinit {
    self.observation = nil
}    

【讨论】:

  • 通知也是同样的问题。如果您使用基于块的方法,您需要在 deinit 中显式地将返回值设置为 nil。非基于块的观察者不需要这样做。
  • 很棒的附录!需要特别说明的是,在较新的 iOS 上没有观察到这个问题,对吧?
  • iOS 11 会自动处理这个问题。我也会假设 iOS 12,但我还没有测试过。
  • @barbarity 你有那个来源吗?
  • 具体是为了什么?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-02-17
  • 2018-12-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多