swift - 何时调用计算属性的 modify 方法,它的作用是什么?
问题描述
考虑以下类定义
class Class1 {
var property: String {
get {
return ""
}
set {
print("set called")
}
}
}
如果您在 get 块中添加断点并读取property
,则执行将暂停,您会观察到调用堆栈中最顶层的方法是Class1.property.getter
同样,如果您在 set 块和 set 中添加断点property
,则执行会暂停,并且您会观察到调用堆栈中最顶层的方法是Class1.property.setter
在调试崩溃时,我观察到调用堆栈中最顶层的方法是ClassName.computedPropertyName.modify
whereClassName
和computedPropertyName
are placeholders。
谁能指出该modify
方法的作用和调用时间?
解决方案
和get
,set
是modify
一个访问器。它是向通用访问器发展的一部分,用于使用 yield-once 协程获取对基础值的可变引用。
实际上,您可以使用关键字modify
在今天的 Swift 中编写访问器。_modify
但是请注意,它还不是官方功能,因此任何显式依赖的代码_modify
都yield
可能在没有通知的情况下被破坏。
class C {
var _property: String = ""
var property: String {
get {
return _property
}
_modify {
yield &_property
}
}
}
let c = C()
c.property += "hello"
print(c.property) // hello
在 mutatingc.property
时,_modify
调用访问器以获取对某些底层存储的可变引用。关键字用于将yield
控制权转移回调用者,并引用_property
's storage。此时,调用者可以对存储应用任意突变,在这种情况下调用+=
. 一旦突变完成,控制权就会转移回_modify
,此时它会返回。
为什么modify
访问器有用?
简而言之,它避免了值的复制,这可能会触发写入时复制类型的昂贵复制操作,例如String
、Array
和(我在这里更详细地Dictionary
讨论了这一点)。通过访问器进行变异允许字符串就地变异,而不是变异一个临时副本,然后将其写回。c.property
modify
为什么要modify
使用协程?
协程的使用允许将可变引用临时交还给调用者,之后访问者可以执行额外的逻辑。
例如:
class C {
var _property: String = ""
var property: String {
get {
return _property
}
_modify {
yield &_property
_property += " world!"
}
}
}
let c = C()
c.property += "hello"
print(c.property) // hello world!
它首先让调用者执行其突变,然后附加" world!"
到字符串的末尾。
为什么modify
访问器会出现在您的代码中?
Swift 编译器可以隐式合成modify
可变属性的访问器。对于具有 getter 和 setter 的计算属性,实现如下所示:
class Class1 {
var property: String {
get {
return ""
}
set {
print("set called")
}
// What the compiler synthesises:
_modify {
var tmp = property.get() // Made up syntax.
yield &tmp
property.set(tmp)
}
}
}
首先调用 getter 以获取值的可变副本,然后将对该可变副本的引用传递回调用者,然后使用新值调用 setter。
在这种modify
情况下,访问器主要用于通过动态调度实现属性的有效变异。考虑以下示例:
class C {
var property = "hello" {
// What the compiler synthesises:
_modify {
yield &property
}
}
}
class D : C {
override var property: String {
get { return "goodbye" }
set { print(newValue) }
// What the compiler synthesises:
_modify {
var tmp = property.get()
yield &tmp
property.set(tmp)
}
}
}
func mutateProperty(_ c: C) {
c.property += "foo"
}
在 mutatingc.property
上,modify
访问器被动态分派到。如果这是 的实例C
,则允许对存储的引用property
直接返回给调用者,从而实现有效的就地突变。如果这是 的实例D
,则调用modify
just 与调用 getter 后跟 setter 的效果相同。
为什么modify
在崩溃的堆栈跟踪中显示为最顶层的调用?
我认为这是因为编译器已将您的 getter 和 setter 的实现内联到modify
访问器中,因此这意味着崩溃可能是由您的属性的 getter 或 setter 的实现引起的。
推荐阅读
- apache-kafka - 手动设置 Kafka 消费者偏移量
- keras - 如何在 Keras 中重新初始化图层而不是权重
- regex - 提取超链接 Google Apps 脚本
- c# - iOS自定义渲染不应用角半径
- reactjs - 使用钩子从道具中反应材料表编辑
- c# - 在 EF Core 中使用语法在 dbcontext 内部或外部启动对象是否重要?
- php - PHP while loop + foreach 在同一页面上加倍结果
- javascript - 用于替换 Twitter 单词的 Chrome 扩展
- python-3.x - 从 AWS config 自动修复操作中排除 s3 存储桶
- prometheus - Prometheus metrics_path 被编码