用于observeValue的Swift 4方法(forKeyPath:...)

问题描述 投票:28回答:2

我一直试图找到一个例子,但我所看到的并不适用于我的情况。

什么是以下代码的等价物:

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
2个回答
71
投票

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

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

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

涉及的类型

密钥路径语法

密钥路径表达式的一般grammar遵循\Type.keyPath形式,其中Type是具体类型名称(包括任何通用参数),keyPath是一个或多个属性,下标或可选链接/强制展开后缀的链。此外,如果可以从上下文推断出keyPath的类型,则可以省略它,从而产生最精悍的\.keyPath

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

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

所有权

你是NSKeyValueObservation函数返回的observe实例的所有者,这意味着你不再需要addObserverremoveObserver了;相反,只要您需要进行观察观察,就可以对它进行强有力的参考。

你也不需要invalidate():优雅的deinit。所以,你可以让它一直存在,直到它持有它的实例死亡,通过niling引用手动停止它,或者甚至调用invalidate()如果你需要保持你的实例存在一些臭的原因。

注意事项

正如你可能已经注意到的那样,观察仍然潜藏在Cocoa的KVO机制的范围内,因此它只适用于Obj-C类和Swift类继承NSObject(每个Swift-dev最喜欢的类型),并且要求你想要观察的任何值,必须标记为@objc(每个Swift-dev最喜欢的属性)并声明为dynamic

话虽这么说,整体机制是一个受欢迎的改进,特别是因为它设法Swiftify从我们可能碰巧需要使用的模块(例如NSObjects)观察进口的Foundation,并且没有冒弱化我们努力获得的表现力的风险每次按键。

作为旁注,Key-Path String Expressions仍需要dynamically access NSObject的财产给KVC或致电value(forKey(Path):)

超越KHA

关键路径表达式比KVO要多得多。 \Type.path表达式可以存储为KeyPath对象,以便以后重用。它们有可写,部分和类型擦除的味道。它们可以增强为构图设计的getter / setter函数的表现力,更不用说它们在允许那些胃部最强的人钻研透镜和棱镜等功能概念的世界中扮演的角色。我建议你查看下面的链接,了解他们可以打开的许多开发门的更多信息。

链接:

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 Foundation 4:35为SKP,19:40为KVO。


6
投票

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

在iOS 10中,您仍然需要在取消分配类之前删除观察者,否则您将崩溃NSInternalInconsistencyException说明:

A的实例C被释放,而关键值观察者仍然在其中注册。

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

deinit {
    self.observation = nil
}    
© www.soinside.com 2019 - 2024. All rights reserved.