Geo*_*e_E 0 automatic-ref-counting swift swiftui
我正在使用onChange(of:perform:)SwiftUI 修饰符。然后我想获得旧值,将其与新值进行比较。我阅读了文档,其中说:
闭包可以捕获先前的值以将其与新值进行比较。
举个例子:
.onChange(of: playState) { [playState] newState in
model.playStateDidChange(from: playState, to: newState)
}
Run Code Online (Sandbox Code Playgroud)
我的问题是为什么在示例中被playState捕获在[ ]? 该playState值无需传入即可轻松访问。此外,这不是类的一部分,因此我认为无法通过捕获self某种类型来创建强引用。
为什么这个例子是这样写的?
在“正常”情况下,在不可变值类型(例如 a struct)中定义的闭包捕获它的值,它不会改变,所以一切都很好。
struct Foo {
var a = "original"
func makeFn() -> () -> Void {
return { print(a) }
}
}
var foo = Foo()
let fn = foo.makeFn()
foo.a = "changed"
fn() // "original"
Run Code Online (Sandbox Code Playgroud)
但是对于@State,实际值存储在 SwiftUI 维护的某个全局存储中,因此它的行为基本上就像具有引用语义一样。
当闭包被调用时,状态值已经改变了,所以print(a)按照上面的方法通过@State属性包装器访问一个值,它检索然后更新的值。
为了解决这个问题,您可以使用捕获列表将该属性捕获到闭包的局部变量中:
return { [a] in print(a) }
Run Code Online (Sandbox Code Playgroud)
这当然是一个简化的例子,SwiftUI 可能在幕后做其他事情,但我认为它传达了这一点。
要查看 SwiftUI 中的差异,请尝试以下操作:
.onChange(of: playState) { [playState] newState in
print(playState, self.playState, newState)
}
Run Code Online (Sandbox Code Playgroud)
输出将是这样的:
original new new
Run Code Online (Sandbox Code Playgroud)
playState是在定义闭包时(即body计算时)捕获的局部变量,self.playState通过 访问该值@State,该值已更改,并且newState显然是具有新值的传入参数。
| 归档时间: |
|
| 查看次数: |
554 次 |
| 最近记录: |