我想知道我是否可以通过 inout 而不是 Binding 使我的 View 函数绑定(bind)自身,是否有可能为我们提供正确/更好的语法?正确知道我得到编译时错误:
Modifying state during view update, this will cause undefined behavior.
这对我来说是可以理解的,我想也许我在这项工作中使用了错误的语法。
PS:我完全了解 Binding 及其用例,如果我们也可以用 inout 解决这个问题,请尝试找到答案。
func TextView(inPutValue: inout Bool) -> some View {
return Text("Hello")
.onTapGesture { inPutValue.toggle() }
}
用例:
struct ContentView: View {
@State private var isOn: Bool = true
var body: some View {
TextView(inPutValue: &isOn)
}
}
更新:
import SwiftUI
struct ContentView: View {
@State private var value: Int = Int() { didSet { print(value.description) } }
var body: some View {
Button("update State via inout") { inoutFunction(incomingValue: &value) }
}
}
func inoutFunction(incomingValue: inout Int) { incomingValue += 1 }
最佳答案
这里不能使用inout
的原因是inout
有一个copy-in-copy-out。行为。该值作为副本传递给函数,一旦函数返回,修改后的副本就会被复制回来。您不应该将其视为按引用传递,认为它可以作为优化以这种方式实现。
现在知道了,Swift 编译器禁止您在转义闭包中使用 inout 参数很有意义,例如在 onTapGesture中使用
。毕竟,修改后的 inPutValue
inPutValue
只会在 TextView
返回时复制回来,而不是在有人点击它时复制回来,因此无论您在 onTapGesture
中对其进行什么修改TextView
的调用者根本不可见。另见 this answer .
因此,一旦 TextView
返回,值就会被复制回调用者。如错误消息所述,不允许在计算 body
时直接修改 @State
(即“在 View 更新期间”)。
现在让我们看一下Button
的情况。请注意,这次对 inoutFunction(incomingValue: &value)
的调用发生在按钮的点击处理程序中,而不是在 body
中 - 这意味着 value
将按下按钮时写入。这是允许的。
您可以通过添加闭包参数使您的 TextView
具有与 Button
的初始化程序类似的形式:
func TextView(update: @escaping () -> Void) -> some View {
return Text("Hello")
.onTapGesture(perform: update)
}
注意这里根本没有inout
,就像Button.init
中没有inout
一样。
然后您可以使用 inout
参数编写您的函数:
func inoutFunction(_ b: inout Bool) {
b.toggle()
}
并使用它:
@State private var isOn = true
var body: some View {
TextView { inoutFunction(incomingValue: &isOn) }
}
请注意,您根本不需要 inout
。
TextView { isOn.toggle() }
关于swift - 如何在 SwiftUI 中使用 inout 而不是 Binding?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66939775/