SwiftUI:不同 View 之间的数据共享

标签 swiftui data-sharing code-separation

在 View 之间共享变量的最佳实践是什么? 我的应用程序只有一个 View 。但随着它变得越来越复杂,我想我应该把它分成几个 View 。还要分离方法。 我从这样的事情开始:

struct ContentView: View {
    @State var str: String = "String"
    var body: some View {
        VStack(alignment: .leading) {
            Text(str)
            TextField("Input", text: $str)
            Button("button", action: { doSomething() })
        }.padding()
    }
    func doSomething() {
        str = str + " " + str
    }
}

想去那里:

class GlobalVars: ObservableObject {
    @Published var str: String = "Initial String"
}
struct ContentView: View {
    @ObservedObject var globalvars = GlobalVars()
    var body: some View {
        VStack(alignment: .leading) {
            DisplayView()
            EditView()
            ControlView()
        }.padding()
    }
}
struct DisplayView: View {
    @Binding var str:  String
    var body: some View {
        Text(self.globalvars.str)
    }
}
struct EditView: View {
    @Binding var str:  String
    var body: some View {
        TextField("Input", text: self.$str)
    }
}
struct ControlView: View {
    @Binding var str:  String
    var body: some View {
        Button("button", action: { doSomething() })
    }
}
func doSomething() {
    @Binding var str:  String
    self.str = self.str + " " + self.str
}

我尝试使用@Published、@ObservedObject 和@Binding。但别明白。感谢您提前提供任何指示。

最佳答案

有多种方法可以解决这个问题。

我的选择可能是将绑定(bind)传递给您需要访问的变量。可能看起来像这样:

class GlobalVars: ObservableObject {
    @Published var str: String = "Initial String"
}
struct ContentView: View {
    @ObservedObject var globalvars = GlobalVars()
    var body: some View {
        VStack(alignment: .leading) {
            DisplayView(str: globalvars.str) //don't need a binding here since it doesn't get modified
            EditView(str: $globalvars.str)
            ControlView(str: $globalvars.str)
        }.padding()
    }
}
struct DisplayView: View {
    var str:  String //don't need a binding here since it doesn't get modified
    var body: some View {
        Text(str)
    }
}
struct EditView: View {
    @Binding var str:  String
    var body: some View {
        TextField("Input", text: $str)
    }
}
struct ControlView: View {
    @Binding var str:  String
    var body: some View {
        Button("button", action: { doSomething() })
    }
    
    func doSomething() {
        str = str + " " + str
    }
}

请注意,现在在 ContentView ,有一个参数传递给每个 subview ,其中包含到 $ 的绑定(bind)(使用 GlobalVars 符号) str属性。

此外,doSomething被移入ControlView的 body


您还可以使用EnvironmentObject 来处理此问题。我个人不太喜欢这种方法,因为我宁愿明确地看到我的参数的去向。它还允许 subview 访问整个 ObservableObject,但这并不是真正必要的。但是,它向您展示了原理:

class GlobalVars: ObservableObject {
    @Published var str: String = "Initial String"
}
struct ContentView: View {
    @ObservedObject var globalvars = GlobalVars()
    var body: some View {
        VStack(alignment: .leading) {
            DisplayView()
            EditView()
            ControlView()
        }.padding()
        .environmentObject(globalvars)
    }
}
struct DisplayView: View {
    @EnvironmentObject var globalvars : GlobalVars
    var body: some View {
        Text(globalvars.str)
    }
}
struct EditView: View {
    @EnvironmentObject var globalvars : GlobalVars
    var body: some View {
        TextField("Input", text: $globalvars.str)
    }
}
struct ControlView: View {
    @EnvironmentObject var globalvars : GlobalVars
    var body: some View {
        Button("button", action: { doSomething() })
    }
    
    func doSomething() {
        globalvars.str = globalvars.str + " " + globalvars.str
    }
}

请注意,现在,globalvars通过将 .environmentObject 放置在 View 层次结构中来传递给子级。每个 subview 都可以通过声明 @EnvironmentObject var globalvars : GlobalVars 属性来访问它。


您还可以采用一种混合模型,将 ObservableObject 作为参数显式传递给 subview :

struct ContentView: View {
    @ObservedObject var globalvars = GlobalVars()
    var body: some View {
        VStack(alignment: .leading) {
            DisplayView(globalvars: globalvars)
        }.padding()
        .environmentObject(globalvars)
    }
}

struct DisplayView: View {
    @ObservedObject var globalvars : GlobalVars
    var body: some View {
        Text(globalvars.str)
    }
}

关于SwiftUI:不同 View 之间的数据共享,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66595880/

相关文章:

javascript - Aurelia:如何使用 npm 包中的 View / View 模型?

ios - 使用 SwiftUI 发送电子邮件

ios - SwiftUI - 从 subview 转换回主视图后删除导航栏中的多余空间

ios - 使用 NavigationView 进行模态演示

docker - 在 Docker 中,如何在容器之间共享文件,然后将它们保存到图像中?

ios - 如何在后台共享应用程序之间的数据?

android - Android 中 Fragments 和 Activity 之间的数据共享

html - vue.js 2 - 将单个文件组件的 html 片段提取到独立文件中

javascript - 所有代码都放在一个 js 文件中 vs 将代码分成多个 js 文件

swift - UIViewRepresentable 没有更新绑定(bind)到 ObservedObject 属性?