aturan23
aturan23

Reputation: 5400

swiftui @State value depends on @ObservedObject ViewModel init error

I have simple viewModel:

final class EmployeeListViewModel: ObservableObject {
 @Published var list = [Employee]()
 init() {
  // some request
  self.list = [Employee, Employee]
 }
}

And have a view:

struct EmployeeView: View {
 @ObservedObject var viewModel = EmployeeListViewModel()
 @State private var showContents: [Bool] = Array(repeating: false, count: viewModel.list.count)// <- error throws here
 var body: some View {
        GeometryReader { fullView in
            ScrollView {
                VStack(spacing: 40) {
                  ForEach(self.viewModel.list) { employee in
                     Text(employee.firstName).foregroundColor(.black)
                  }
                }
            }
        }
 }
}

Error text:

Cannot use instance member 'viewModel' within property initializer; property initializers run before 'self' is available

I tried change it with init:

struct EmployeeView: View {
 @ObservedObject var viewModel = EmployeeListViewModel()
 @State private var showContents: [Bool]

 init() {
        _showContents = State(initialValue: Array(repeating: false, count: viewModel.list.count)) // <- error
    }

 var body: some View {
        GeometryReader { fullView in
            ScrollView {
                VStack(spacing: 40) {
                  ForEach(self.viewModel.list) { employee in
                     Text(employee.firstName).foregroundColor(.black)
                  }
                }
            }
        }
 }
}

But it also throws error:

'self' used before all stored properties are initialized

this throws on I call viewModel on init()

How to solve it? @State i use for card view. There I simplified views for easy understand.

Upvotes: 3

Views: 1054

Answers (2)

Joakim Danielson
Joakim Danielson

Reputation: 51920

First initialise the state variable to an empty array

@State private var showContents: [Bool] = []

then set it in the init

init() {
    showContents = Array(repeating: false, count: viewModel.list.count)
 }

You shouldn't initialise the view model property in the view but rather use dependency injection

init(viewModel: EmployeeListViewModel) {
    self.viewModel = viewModel
    showContents = Array(repeating: false, count: viewModel.list.count)
}

Upvotes: 1

Asperi
Asperi

Reputation: 257703

Here is possible solution

struct EmployeeView: View {
 @ObservedObject var viewModel: EmployeeListViewModel     // << declare
 @State private var showContents: [Bool]                  // << declare

 init() {
       let vm = EmployeeListViewModel()   // create here !!

       // initialize both below
       self.viewModel = vm                     
       self._showContents = State(initialValue: Array(repeating: false, 
              count: vm.list.count))
    }

Upvotes: 0

Related Questions