Swift observeValue(forKeyPath:...) 的 4 种方法
Swift 4 approach for observeValue(forKeyPath:...)
我一直在努力寻找示例,但我所看到的不适用于我的情况。
以下代码的等价物是什么:
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 收到警告:
Prefer the new block based KVO API with keypaths when using Swift 3.2 or later.
如果你能指出正确的方向,我将不胜感激。
Swift 4 介绍了继承 NSObject
.
的 class 可用的一系列具体 Key-Path types, a new Key-Path Expression to produce them and a new closure-based observe 函数
使用这组新功能,您的特定示例现在可以更简洁地表达:
self.observation = object.observe(\.keyPath) {
[unowned self] object, change in
self.someFunction()
}
涉及的类型
observation:
NSKeyValueObservation
change:
NSKeyValueObservedChange
\.keyPath
: KeyPath class 在编译时产生的一个实例。
关键路径语法
键路径表达式的一般 grammar 遵循 \Type.keyPath
形式,其中 Type
是具体类型名称(包括任何通用参数),keyPath
一个或多个属性、下标或可选的 chaining/forced 展开后缀的链。此外,如果可以从上下文中推断出 keyPath 的类型,则可以将其省略,从而得到最简洁的 \.keyPath
.
这些都是有效的键路径表达式:
\SomeStruct.someValue
\.someClassProperty
\.someInstance.someInnerProperty
\[Int].[1]
\[String].first?.count
\[SomeHashable: [Int]].["aStringLiteral, literally"]!.count.bitWidth
所有权
您是 NSKeyValueObservation
实例 observe
函数 returns 的所有者,这意味着,您不必 addObserver
也不再是 removeObserver
;相反,只要您需要观察观察,您就会一直强烈引用它。
您不需要 invalidate()
:它会deinit
优雅。因此,您可以让它一直存在,直到持有它的实例死亡,通过 nil
ing 引用手动停止它,或者甚至调用 invalidate()
如果您出于某些臭名昭著的原因需要让您的实例保持活动状态。
注意事项
您可能已经注意到,观察仍然潜伏在 Cocoa 的 KVO 机制的范围内,因此它仅适用于 Obj-C classes 和 Swift classes 继承了 NSObject
(每个 Swift-dev 最喜欢的类型)并附加要求您打算观察的任何值必须标记为 @objc
(每个 Swift -dev 最喜欢的属性)并声明 dynamic
.
也就是说,整体机制是一个受欢迎的改进,特别是因为它设法 Swift 化观察从我们可能碰巧需要使用的模块中导入的 NSObjects
(例如 Foundation
),并且在不冒削弱表达能力的风险的情况下,我们努力在每次击键时获得。
作为旁注,Key-Path String Expressions are still required to dynamically access NSObject
的属性到 KVC 或调用 value(forKey(Path):)
超越KVO
键路径表达式比 KVO 多得多。 \Type.path
表达式可以存储为 KeyPath
对象供以后重用。它们有可写的、部分的和类型擦除的风格。它们可以增强 getter/setter 为组合而设计的函数的表达能力,更不用说它们在让那些胃口最强的人深入研究透镜和棱镜等函数概念世界方面所发挥的作用了。我建议您查看下面的链接,了解更多有关它们可以打开的许多开发大门的信息。
链接:
Key-Path Expression @ docs.swift.org
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 Foundation 4:35 SKP 和 19:40 KVO。
在 iOS 10.
中使用此方法时我的应用程序崩溃时,我在答案中添加了一些内容
在 iOS 10 中,您仍然需要在释放 class 之前删除观察者,否则您将遇到崩溃 NSInternalInconsistencyException
声明:
An instance A
of Class C
was deallocated while key value observers were still registered with it.
为了避免这次崩溃。只需将您正在使用的观察者 属性 设置为 nil
.
deinit {
self.observation = nil
}
我一直在努力寻找示例,但我所看到的不适用于我的情况。
以下代码的等价物是什么:
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 收到警告:
Prefer the new block based KVO API with keypaths when using Swift 3.2 or later.
如果你能指出正确的方向,我将不胜感激。
Swift 4 介绍了继承 NSObject
.
使用这组新功能,您的特定示例现在可以更简洁地表达:
self.observation = object.observe(\.keyPath) {
[unowned self] object, change in
self.someFunction()
}
涉及的类型
observation:
NSKeyValueObservation
change:
NSKeyValueObservedChange
\.keyPath
: KeyPath class 在编译时产生的一个实例。
关键路径语法
键路径表达式的一般 grammar 遵循 \Type.keyPath
形式,其中 Type
是具体类型名称(包括任何通用参数),keyPath
一个或多个属性、下标或可选的 chaining/forced 展开后缀的链。此外,如果可以从上下文中推断出 keyPath 的类型,则可以将其省略,从而得到最简洁的 \.keyPath
.
这些都是有效的键路径表达式:
\SomeStruct.someValue
\.someClassProperty
\.someInstance.someInnerProperty
\[Int].[1]
\[String].first?.count
\[SomeHashable: [Int]].["aStringLiteral, literally"]!.count.bitWidth
所有权
您是 NSKeyValueObservation
实例 observe
函数 returns 的所有者,这意味着,您不必 addObserver
也不再是 removeObserver
;相反,只要您需要观察观察,您就会一直强烈引用它。
您不需要 invalidate()
:它会deinit
优雅。因此,您可以让它一直存在,直到持有它的实例死亡,通过 nil
ing 引用手动停止它,或者甚至调用 invalidate()
如果您出于某些臭名昭著的原因需要让您的实例保持活动状态。
注意事项
您可能已经注意到,观察仍然潜伏在 Cocoa 的 KVO 机制的范围内,因此它仅适用于 Obj-C classes 和 Swift classes 继承了 NSObject
(每个 Swift-dev 最喜欢的类型)并附加要求您打算观察的任何值必须标记为 @objc
(每个 Swift -dev 最喜欢的属性)并声明 dynamic
.
也就是说,整体机制是一个受欢迎的改进,特别是因为它设法 Swift 化观察从我们可能碰巧需要使用的模块中导入的 NSObjects
(例如 Foundation
),并且在不冒削弱表达能力的风险的情况下,我们努力在每次击键时获得。
作为旁注,Key-Path String Expressions are still required to dynamically access NSObject
的属性到 KVC 或调用 value(forKey(Path):)
超越KVO
键路径表达式比 KVO 多得多。 \Type.path
表达式可以存储为 KeyPath
对象供以后重用。它们有可写的、部分的和类型擦除的风格。它们可以增强 getter/setter 为组合而设计的函数的表达能力,更不用说它们在让那些胃口最强的人深入研究透镜和棱镜等函数概念世界方面所发挥的作用了。我建议您查看下面的链接,了解更多有关它们可以打开的许多开发大门的信息。
链接:
Key-Path Expression @ docs.swift.org
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 Foundation 4:35 SKP 和 19:40 KVO。
在 iOS 10.
中使用此方法时我的应用程序崩溃时,我在答案中添加了一些内容在 iOS 10 中,您仍然需要在释放 class 之前删除观察者,否则您将遇到崩溃 NSInternalInconsistencyException
声明:
An instance
A
of ClassC
was deallocated while key value observers were still registered with it.
为了避免这次崩溃。只需将您正在使用的观察者 属性 设置为 nil
.
deinit {
self.observation = nil
}