Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SwiftUI passing data into ViewModel

Tags:

swiftui

I am trying to put the data that I am passing into the view into the ViewModel.

I see lots of tutorial about retrieving data from outside sources like Json or Firebase but nothing about using my data passed from the previous page.

I have to do a lot of calculations on the data to get my final output.

here I need to get 'entry' into the ShowViewModel.

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

I am just playing with a blank ViewModel here for testing.

class ShowViewModel: ObservableObject {

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

}
like image 484
diogenes Avatar asked Aug 28 '20 07:08

diogenes


2 Answers

You may try the following:

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
    }
}

Now when you create your view you need to pass EntryData to it:

ShowView(entry: EntryData())
like image 116
pawello2222 Avatar answered Oct 16 '22 07:10

pawello2222


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){
    }
}

Then create it in your ContentView like:

struct ContentView {
    @State var config = ShowViewConfig()
     var body: some View {
          ...
          ShowView(config:$config)

Then use it in your ShowView like:

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

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

enter image description here

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.

enter image description here

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

enter image description here

like image 33
malhal Avatar answered Oct 16 '22 08:10

malhal