SwiftUI — передача контекста управляемого объекта в модель

#swiftui #nsmanagedobjectcontext

#swiftui #nsmanagedobjectcontext

Вопрос:

Передать контекст управляемого объекта в представление в SwiftUI достаточно просто, используя переменную @Environment. Но получение того же контекста для модели и модели представления, не так много. Вот что я пробовал:

Я создал свойство с именем context в модели представления. В представлении я передаю контекст управляемого объекта лениво. Проблема в том, что теперь я получаю сообщение об ошибке при вызове метода модели представления из представления — «Невозможно использовать изменяющийся геттер для неизменяемого значения: ‘self’ неизменяем». Метод работал до того, как я добавил контекст, так почему же он перестал работать? И, что более важно, как мне заставить это работать?!

Модель:

 struct Model {

   //use fetch request to get users

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

Просмотр модели:

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

И, наконец, представление:

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

Ответ №1:

Вы не можете использовать lazy var в представлении, потому что оно неизменяемо. Вот возможный подход к решению вашего случая

 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
        }

    }
}
  

Комментарии:

1. Это работает, но поскольку модель представления не работает без контекста, у нас не должно быть пустого инициализатора, который позволяет это. Я думаю, что Apple скоро представит механизм для передачи переменных среды из представлений SwiftUI в пользовательские типы (например, модели представлений).