swift 从方案中突变自变量

enxuqcxy  于 2023-02-15  发布在  Swift
关注(0)|答案(1)|浏览(121)
protocol: MyProtocol {
    var showView: Bool { get set }
}

struct MyView: View, MyProtocol {
    var showView = false
    var body: some View {
        ZStack(){
            AnotherView(myProtocol: self)
            if showView {
                // code
            }
        }
    }
}

struct AnotherView: View {
    var myProtocol: MyProtocol
    var body: some View {
        ZStack(){
            Text("Text")
                .onTapGesture{
                    myProtocol.showView = true  // xcode complains on this line
                }
        }
    }
}

我有上面的代码,我想当Text被点击时,showView变量改变值,然后做我想做的任何事情
这不是我的实际代码,只是一个最小的复制示例,我不得不使用protocol,因为AnotherView是一个可以从多个方面使用的可重用视图,所以我只想更改当前父视图的showView
但是XCode一直在抱怨,说:
无法分配给属性:"self"是不可变的
如何从子视图更改父视图协议属性的值?

f0ofjuux

f0ofjuux1#

你应该检查一下你的“最小复制示例”是否产生了你描述的错误。你的示例没有,因为MyProtocol声明中有语法错误。正确的声明是

protocol MyProtocol {
    var showView: Bool { get set }
}

更正该错误将导致您描述的错误。
SwiftUI视图中的可变状态需要存储在某种DynamicProperty中,最常见的是使用属性 Package 器@State@Binding@ObservedObject之一。
但是很难理解如何修复您的示例,因为在您的示例中,您有一个MyView,它将自己传递给AnotherView,并期望AnotherView改变传入的MyView。这并不是SwiftUI的设计工作方式。在SwiftUI中,可变状态需要更清晰地与视图分离。
也许这正好抓住了你想要达到的效果:

struct MyViewState: MyProtocol {
    var showView = false
}

struct MyView: View {
    @State var state: any MyProtocol = MyViewState()
    
    var body: some View {
        ZStack(){
            AnotherView(myProtocol: $state)
            
            if state.showView {
                // code
            }
        }
    }
}

struct AnotherView: View {
    @Binding var myProtocol: any MyProtocol
    var body: some View {
        ZStack {
            Text("Text")
                .onTapGesture {
                    myProtocol.showView = true  // xcode complains on this line
                }
        }
    }
}

注意,因为AnotherView需要一个MyProtocol存在,所以我必须显式地声明stateMyView中的一个存在(any MyProtocol),你可以通过观看WWDC 2022: Embrace Swift genericsWWDC 2022: Design protocol interfaces in Swift来学习更多关于存在的知识。
最好避免在这里使用存在式,而是将AnotherView设置为泛型,如下所示:

struct MyView: View {
    @State var state = MyViewState()
    
    var body: some View {
        ZStack(){
            AnotherView(myProtocol: $state)
            
            if state.showView {
                // code
            }
        }
    }
}

struct AnotherView<My: MyProtocol>: View {
    @Binding var myProtocol: My
    var body: some View {
        ZStack {
            Text("Text")
                .onTapGesture {
                    myProtocol.showView = true  // xcode complains on this line
                }
        }
    }
}

相关问题