1

I have created a ViewModel with an init() that accepts a parameter something like this. PS: Learning swift and swiftUI

//UsersViewModel.swift
class UsersViewModel: ObservableObject {
  @Published var users: [User]
  @Published var category: String
  init(category: String) {
    self.category = continentcategory
    self.users = UserData().getUsers(byCategory: category)
  }
}  

UserData is the Data Model where I have a function getUsers(byCategory) that allows me to get a subset of data instead of all data and then filtering it.

For my SwiftUI view

//UserListByCategory.swift

import SwiftUI
struct UserListByCategory: View {
    @EnvironmentObject var ud: UsersViewModel
    var body: some View {
        Text("Hello")
    }
}

struct UserListByCategory_Previews: PreviewProvider {
    static var previews: some View {
        UserListByCategory()
            .environmentObject(UsersViewModel(category: "Office"))
    }
}

This above SwiftUI View gets called by another ListView after the user selects a category. How do I pass that category without hardcoding it here?

1 Answers1

1

In SwiftUI we don't use view model objects for our view data. View structs are our primary encapsulation mechanism, e.g.

If you need to fetch your data:

struct UserListByCategory: View {

    let category: String
    @State var users: [User] = []
    @State var message = ""

    var body: some View {
        List {
            ForEach(users) { user in
                Text("\(user.name)")
            }
        }
        .task(id: category) {
            do {
              users = try await User.fetchUsers(category: category)
              message = ""
            }
            catch {
                message = "Failed"
            }
        }
    }
}

If you already have all the model data, pass it down the View struct hierarchy as follows:

struct ContentView: View {
    @ObservedObject var model: Model
    var body: some View {
        UserList(users: model.users(category:"Office"))
    }
}

struct UserList: View {
    let users: [User]

    var body: some View {
        List {
            ForEach(users) { user in
                Text("\(user.name)")
            }
        }
    }
}
malhal
  • 26,330
  • 7
  • 115
  • 133
  • 1
    Thank you. So initialize and then fetch what you need. – Vandan Desai Jan 10 '22 at 20:54
  • 1
    What I'm trying to do is create a Model that typically will get everything. And then have different ViewModels to get data that is required, once users start navigating to other pages. – Vandan Desai Jan 10 '22 at 20:54
  • 1
    In SwiftUI we have Model and View data. There is no need for ViewModels because there isn't even a View in the traditional sense. SwiftUI automatically generates the View on screen by calculating and diffing the View data struct hierarchy. Just access your Model from a high level View and pass down what you need via the View hierarchy converting from rich model types to simple types. – malhal Jan 10 '22 at 21:09
  • 1
    Understood, thank you – Vandan Desai Jan 10 '22 at 22:53
  • 1
    Just realized that I was missing a line in my class file class UsersViewModel: ObservableObject { – Vandan Desai Jan 11 '22 at 01:40