如何在 SwiftUI 中使用 inout 而不是 Binding?

use*_*ser 3 swift swiftui

我想知道是否可以让我的视图函数通过 inout 而不是 Binding 来绑定自身,对我们来说是否可以使用正确/更好的语法?正确知道我收到编译时错误:

Modifying state during view update, this will cause undefined behavior.
Run Code Online (Sandbox Code Playgroud)

这对我来说是可以理解的,我想也许我在这项工作中使用了错误的语法。

PS:我完全了解 Binding 及其用例,如果我们也可以使用 inout 来完成此问题,请尝试找到答案。


func TextView(inPutValue: inout Bool) -> some View {

    return Text("Hello")
        .onTapGesture { inPutValue.toggle() }
    
}
Run Code Online (Sandbox Code Playgroud)

用例:

struct ContentView: View {

    @State private var isOn: Bool = true

    var body: some View {
        
        TextView(inPutValue: &isOn)
 
    }
    
}
Run Code Online (Sandbox Code Playgroud)

更新:

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 }
Run Code Online (Sandbox Code Playgroud)

Swe*_*per 5

您不能在此处使用的原因inout是因为inout具有复制输入复制输出行为。该值作为副本传递到函数中,函数一返回,修改后的副本就会被复制回来。您不应该将其视为按引用传递,认为可以通过这种方式实现优化。

inPutValue现在知道了这一点,对于 Swift 编译器来说,禁止您在转义闭包中使用 inout 参数(例如使用in )是很有意义的onTapGesture。毕竟,修改后的内容inPutValue只会在TextView返回时复制回来,而不是在有人点击它时复制回来,因此您对它所做的任何修改onTapGesture对于调用者来说根本不可见TextView。另请参阅此答案

因此,一旦TextView返回,该值就会被复制回调用者。正如错误消息所示,不允许@State在计算时(即“视图更新期间”)直接修改 a 。body

现在我们来看一下案例Button。请注意,这一次,对 的调用inoutFunction(incomingValue: &value)发生在按钮的单击处理程序内部,而不是 in body- 意味着value按下按钮时将被写入。这是允许的。

您可以通过添加闭包参数来使您的TextViewto 具有与 的初始化程序类似的形式:Button

func TextView(update: @escaping () -> Void) -> some View {

    return Text("Hello")
        .onTapGesture(perform: update)
    
}
Run Code Online (Sandbox Code Playgroud)

inout请注意,其中根本没有任何内容,就像inout中什么也没有一样Button.init

然后您可以使用参数编写函数inout

func inoutFunction(_ b: inout Bool) {
    b.toggle()
}
Run Code Online (Sandbox Code Playgroud)

并使用它:

@State private var isOn = true

var body: some View {
    TextView { inoutFunction(incomingValue: &isOn) }
}
Run Code Online (Sandbox Code Playgroud)

请注意,您根本不需要。 inout

TextView { isOn.toggle() }
Run Code Online (Sandbox Code Playgroud)