SwiftUI-管理対象オブジェクトのコンテキストをモデルに渡す

Aug 24 2020

@Environment変数を使用すると、管理対象オブジェクトのコンテキストをSwiftUIのビューに渡すのは簡単です。しかし、同じコンテキストをモデルとビューモデルに取得することは、それほど多くはありません。これが私が試したものです:

ビューモデルにcontextというプロパティを作成しました。ビューでは、管理対象オブジェクトのコンテキストを遅延的に渡します。問題は、ビューからビューモデルのメソッドを呼び出すと、「不変の値でミューティングゲッターを使用できません: 'self'は不変です」というエラーが発生することです。コンテキストを追加する前にメソッドが機能したのに、なぜ機能しなくなったのですか?そして、もっと重要なのは、どうすればそれを機能させることができるのでしょうか?!

モデル:

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

モデルの表示:

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

回答

Asperi Aug 24 2020 at 16:31

lazy var不変であるため、Viewでは使用できません。これがあなたのケースを解決するための可能なアプローチです

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
        }

    }
}