首页 > 解决方案 > 将 fetch req 和更新核心数据移动到模型

问题描述

如何将核心数据中的获取请求和更新值移动到模型中?

我有核心数据,比如说登录数据(userToken、isLogin 和 userType)。我需要在 2 视图中显示和更新这些数据。所以我需要多次创建更新、保存和获取请求。也许在登录视图和个人资料视图中。

是否可以使用模型从我的核心数据中更新、保存、删除和获取请求?

import SwiftUI

struct LoginView: View {
  @State var isNavigationBarHidden: Bool = true
  @Environment(\.managedObjectContext) private var viewContext
  @FetchRequest(sortDescriptors: [])
  private var userData: FetchedResults<LoginData>
  
  var body: some View {
    ZStack {
      Color.green
      Button(action: {
        setLogin()
      }){
        Text("Login Screen")
          .foregroundColor(Color.black)
      }
    }
    .navigationBarTitle("Hidden Title")
    .navigationBarHidden(self.isNavigationBarHidden)
    .onAppear {
      self.isNavigationBarHidden = true
    }
  }
  
  private func saveContext() {
    do {
      try viewContext.save()
    } catch {
      let error = error as NSError
      fatalError("Unresolved error \(error)")
    }
  }
  
  private func setLogin(){
    let newUser = LoginData(context: viewContext)
    newUser.isLogin = true
    newUser.userToken = "JWT_TOKEN"
    
    saveContext()
  }
}

struct LoginView_Previews: PreviewProvider {
  static var previews: some View {
    LoginView()
  }
}

我想把它放在我的模型中

@Environment(\.managedObjectContext) private var viewContext
@FetchRequest(sortDescriptors: [])
private var userData: FetchedResults<LoginData>

private func saveContext() {
  do {
    try viewContext.save()
  } catch {
    let error = error as NSError
    fatalError("Unresolved error \(error)")
  }
}
  
private func setLogin(){
  let newUser = LoginData(context: viewContext)
  newUser.isLogin = true
  newUser.userToken = "JWT_TOKEN"
   
  saveContext()
}

我已经这样尝试了。

import SwiftUI

class UserDataModel: ObservableObject {
  @Environment(\.managedObjectContext) private var viewContext
  @FetchRequest(sortDescriptors: [])
  var loginData: FetchedResults<LoginData>
  
  func saveContext() {
    do {
      try viewContext.save()
    } catch {
      let error = error as NSError
      fatalError("Unresolved error \(error)")
    }
  }
  
  func setLogin(){
    let newUser = LoginData(context: viewContext)
    newUser.isLogin = true
    newUser.userToken = "JWT_TOKEN"
    
    saveContext()
  }
  
  func setLogout(){
    viewContext.delete(loginData[0])
    saveContext()
  }
}

但它告诉我错误。

Thread 1: Fatal error: Unresolved error Foundation._GenericObjCError.nilError

标签: core-dataswiftui

解决方案


为了让事情变得更简单,您可以在ObservableObject.

class Publisher: ObservableObject {
    static let shared: Publisher = Publisher()
    let container: NSPersistentContainer
    lazy var context = container.viewContext

    @Published var isLoading: Bool = false

    init() {
        self.container = NSPersistentContainer(name: "CoreDataModelName")
    
        container.loadPersistentStores { (storeDescription, error) in
        if let error = error as NSError? {
            fatalError("Unresolved error: \(error)")
            }
        }
    }
}

然后将其设置为managedObjectContext使用environment视图修饰符:
尝试在视图层次结构中尽早设置它,以便其余视图可以访问它

struct ContentView: View {
    @StateObject // or @ObservedObject
    var publisher: Publisher = .shared

    var body: some View {
        Text("Hello World!")
        // set `managedObjectContext` here
        .environment(\.managedObjectContext, publisher.context)
    }
}

然后,您应该可以跨多个视图访问视图上下文:

struct ChildView: View {
    @Environment(\.managedObjectContext)
    private var viewContext // Use the environment object `managedObjectContext`
    @FetchRequest(sortDescriptors: [])
    private var objects: FetchedResults<Object>

    var body: some View {
        Text(“Hello World!”)
    }

    private func saveContext() {
        do {
            try viewContext.save()
        } catch {
            let error = error as NSError
            fatalError("Unresolved error \(error)")
        }
    }

    private func saveObject() {
        let object = Object(context: viewContext)
        saveContext()
    }
}

而且,还可以在您的ObservableObject班级中访问:

extension Publisher {
    /// Function used to update the current state of the app.
    func update(_ perform: (() -> Void)? = nil) {
        DispatchQueue.main.async { [self] in
            isLoading = true
            perform?()
            isLoading = false
        }
    }
    func saveContext() {
        update { [self] in
            do {
                try context.save()
            } catch {
                let error = error as NSError
                debugPrint(error.localizedDescription)
            }
        }
    }
    func save(object: Object) {
        context.insert(object)
        saveContext()
    }
    func delete(object: Object) {
        context.delete(object)
        saveContext()
    }
}

推荐阅读