>我一直在试图找到一个例子,但我所看到的在我的情况下不起作用。
相当于以下代码:
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 4 引入了一系列具体的键路径类型、一个新的键路径表达式来生成它们,以及一个新的基于闭包的观察函数,可用于继承NSObject
的类。
使用这组新功能,您的特定示例现在可以更简洁地表达:
self.observation = object.observe(.keyPath) {
[unowned self] object, change in
self.someFunction()
}
涉及的类型
observation:
NSKeyValueObservation
change:
NSKeyValueObservedChange
.keyPath
:编译时生成的 KeyPath 类的实例。
键路径语法
键路径表达式的一般语法遵循以下形式Type.keyPath
其中Type
是具体的类型名称(包括任何泛型参数),keyPath
一个或多个属性、下标或可选链接/强制解包后缀的链。此外,如果可以从上下文中推断出 keyPath 的类型,则可以省略它,从而产生最简洁的.keyPath
。
这些都是有效的键路径表达式:
SomeStruct.someValue
.someClassProperty
.someInstance.someInnerProperty
[Int].[1]
[String].first?.count
[SomeHashable: [Int]].["aStringLiteral, literally"]!.count.bitWidth
所有权
你是observe
函数返回的NSKeyValueObservation
实例的所有者,这意味着,你不必再addObserver
也不必再removeObserver
;相反,只要你需要观察观察,你就保持对它的强引用。
您也不需要invalidate()
:它会优雅地deinit
。因此,您可以让它存活直到持有它的实例死亡,通过nil
引用手动停止它,或者如果您出于某种臭原因需要保持实例处于活动状态,甚至可以调用invalidate()
。
警告
您可能已经注意到,观察仍然潜伏在 Cocoa 的 KVO 机制范围内,因此它仅适用于继承NSObject
的 Obj-C 类和 Swift 类(每个 Swift-dev 最喜欢的类型),并增加了一个要求,即您打算观察的任何值都必须标记为@objc
(每个 Swift-dev 最喜欢的属性)并声明dynamic
。
话虽如此,整体机制是一个受欢迎的改进,特别是因为它设法 Swiftify 观察我们可能碰巧需要使用的模块导入NSObjects
(例如。Foundation
),并且不会削弱我们努力通过每次击键获得的表现力。
作为旁注,仍然需要键路径字符串表达式来动态访问NSObject
的属性到 KVC 或调用value(forKey(Path):)
超越韩国国际空间组织
键路径表达式比 KVO 要多得多。Type.path
表达式可以存储为KeyPath
对象以供以后重用。它们有可写、部分和类型擦除的口味。它们可以增强专为构图设计的吸气/二传手功能的表现力,更不用说它们在让胃部最强的人深入研究镜片和棱镜等功能概念的世界方面所扮演的角色。我建议您查看下面的链接,以了解有关他们可以打开的许多开发之门的更多信息。
链接:
键路径表达式 @ docs.swift.org
KVO docs @ Apple
Swift Evolution Smart KeyPath 提案
Ole Begemann 的 Whats-new-in-Swift-4 操场,带有 Key-Path 示例
WWDC 2017 视频:基金会新增功能SKP 4:35 和 KVO 19:40。
在 iOS 10 中使用此方法时,我在应用程序上遇到崩溃时,为答案添加一些内容。
在 iOS 10 中,您仍然需要在解除分配类之前删除观察器,否则您将收到崩溃NSInternalInconsistencyException
指出:
类
C
的实例A
被解除分配,而键值观察者仍在其中注册。
为了避免这种崩溃。只需设置用于nil
的观察者属性。
deinit {
self.observation = nil
}