SwiftUI 将数据传递到 ViewModel

dio*_*nes 9 swiftui

我正在尝试将传递到视图中的数据放入 ViewModel。

我看到很多关于从 Json 或 Firebase 等外部来源检索数据的教程,但没有关于使用我从上一页传递的数据的教程。

我必须对数据进行大量计算才能获得最终输出。

在这里,我需要“进入”ShowViewModel。

struct ShowView: View {
  
    @ObservedObject var entry:EntryData
 
    var showVM = ShowViewModel()
 
    var body: some View {
   
       Text("\(entrybeg)")
    
    }
}
Run Code Online (Sandbox Code Playgroud)

我只是在这里玩一个空白的 ViewModel 进行测试。

class ShowViewModel: ObservableObject {

    @Published var test = "something"
    @Published var m:Month = Month()

}
Run Code Online (Sandbox Code Playgroud)

非常感谢!!!

paw*_*222 6

您可以尝试以下操作:

struct ShowView: View {
    @ObservedObject var entry: EntryData

    @ObservedObject var showVM: ShowViewModel // declare only (@ObservedObject optionally)
    
    init(entry: EntryData) {
        self.entry = entry
        self.showVM = ShowViewModel(entry: entry)
    }

    var body: some View {
        Text("\(entrybeg)")
    }
}

class ShowViewModel: ObservableObject {
    @Published var test = "something"
    @Published var m: Month = Month()
    
    private var entry: EntryData
    
    init(entry: EntryData) {
        self.entry = entry
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,当您创建视图时,您需要传递EntryData给它:

ShowView(entry: EntryData())
Run Code Online (Sandbox Code Playgroud)

  • 您不得在 View init 中初始化对象。使用 SwiftUI,当 View 结构发生更改时,会初始化 View 结构,渲染实际视图并销毁 View 结构。因此,您在 View 结构中初始化的任何对象都会立即丢失。您必须使用属性包装器将它们存储在其他地方以保持对象处于活动状态,例如 @StateObject var showVM = ShowViewModel() 这实际上会初始化对象一次,并在每次由父 View 的主体重新创建时将其提供给 View 结构。如果视图没有被重新创建,例如它位于一个 if 变为 false 的内部,那么 StateObject 就会被 deinit。 (4认同)
  • 你太棒了 - 你不知道我今天看了多少小时的 YouTube 视频! (2认同)

mal*_*hal 6

SwiftUI doesn't use the View Model pattern, you have to learn something new. SwiftUI uses lightweight data structs (badly named as Views) that are created super fast, tell the system how to create the actual views shown on screen and then are thrown away immediately and if you follow Apple's tutorials they state that the "Views are very cheap, we encourage you to make them your primary encapsulation mechanism" (20:50 Data Essentials) . You can also group related properties into their own custom struct so that a change to any property is detected as a change to the struct itself, this is called value semantics which is a feature of structs you cannot get with objects like view model objects. Define a struct var with @State in parent View and reference it in child view using @Binding passing it in using the $ syntax. These property wrappers allow the struct to behave like an object reference. SwiftUI does dependency tracking and if any @State or @Binding that is referenced by the body method, body will be called whenever these properties change.

struct ShowViewConfig {
    var test = "something"
    var m:Month = Month()

    // you can even put a method in to update it
    mutating func fetch(name:String, ascending: Bool){
    }
}
Run Code Online (Sandbox Code Playgroud)

Then create it in your ContentView like:

struct ContentView {
    @State var config = ShowViewConfig()
     var body: some View {
          ...
          ShowView(config:$config)
Run Code Online (Sandbox Code Playgroud)

Then use it in your ShowView like:

struct ShowView: View {
    @Binding var config : ShowViewConfig
    var body: some View {
       Text("\(config.test)")
    }
}
Run Code Online (Sandbox Code Playgroud)

You can see this pattern at 8:44 in Data Essentials in SwiftUI WWDC 2020

在此输入图像描述

If you have a model object, i.e. that is being monitored by @ObservableObject then your job is to convert from the rich data types to simple data types in a View struct somewhere in the hierarchy, using formatters if necessary. You can learn more about this in WWDC 2020 Structure your app for SwiftUI previews @ 11:22. So as you can see if you tried to do this in a View Model object instead of the View structs then that is the wrong approach.

在此输入图像描述

It's also fine to use @ObservableObject for a loader or fetcher (20:14 Data Essentials).

在此输入图像描述

  • 正如我之前评论的那样,您发现这个问题并添加更新的答案很有帮助。但请不要对所有答案投否决票来宣传您的答案 - 其他答案在回答时完全有效(并且仍然有效 - SwiftUI 2 仍处于测试阶段)。如果您想表达自己的观点,您对其他答案的评论也可以包含在答案的顶部。 (7认同)