SwiftUI: passaggio del contesto dell'oggetto gestito al modello

Aug 24 2020

Il passaggio di un contesto oggetto gestito a una vista in SwiftUI è abbastanza semplice utilizzando una variabile @Environment. Ma ottenere lo stesso contesto per il modello e il modello di visualizzazione, non così tanto. Ecco cosa ho provato:

Ho creato una proprietà chiamata contesto nel modello di visualizzazione. Nella visualizzazione, passo pigramente il contesto dell'oggetto gestito. Il problema è che ora ricevo un errore quando chiamo il metodo di un modello di visualizzazione dalla vista: "Non è possibile utilizzare getter mutante su un valore immutabile: 'self' è immutabile". Il metodo ha funzionato prima di aggiungere il contesto, quindi perché ha smesso di funzionare? E, cosa più importante, come faccio a farlo funzionare ?!

Modello:

struct Model {

   //use fetch request to get users

   func checkLogin(username: String, password: String) {
      for user in users { 
        if username == user.userEmail && password == user.password {
            return true
        }
    }
    return false
   }
}

Visualizza modello:

class ViewModel {
   var context: NSManagedObjectContext
   private var model = Model()

   init(context: NSManagedObjectContext) {
      self.context = context 
   }

   func checkLogin(username: String, password: String) -> Bool {
      model.checklogin(username: username, password: password)
   }
}

E infine, la vista:

struct LoginView: View {
   @Environment(\.managedObjectContext) var moc
   lazy var viewModel = ViewModel(context: moc) 

    //Login form
    
    Button(action: {
       if self.viewModel.checkLogin(username: self.email, password: self.password) { 
       //ERROR: Cannot use mutating getter on immutable value: 'self' is immutable
          //allow login
       }
    }) {
        Text("login")
    }
}

Risposte

Asperi Aug 24 2020 at 16:31

Non è possibile utilizzarlo lazy varin View, perché è immutabile. Ecco un possibile approccio per risolvere il tuo caso

class ViewModel {
   var context: NSManagedObjectContext?
   private var model = Model()

   init(context: NSManagedObjectContext? = nil) {
      self.context = context
   }

   func checkLogin(username: String, password: String) -> Bool {
      return model.checkLogin(username: username, password: password)
   }
}

struct LoginView: View {
   @Environment(\.managedObjectContext) var moc

   private let viewModel = ViewModel()   // no context yet here, so just default

    //Login form
    var body: some View {
        Button(action: {
           if self.viewModel.checkLogin(username: self.email, password: self.password) {
              //allow login
           }
        }) {
            Text("login")
        }
        .onAppear {
            self.viewModel.context = moc  // << set up context here
        }

    }
}