简体   繁体   English

Swiftui - 在 ObservableObject 中调用 Coredata

[英]Swiftui - Calling Coredata in ObservableObject

I am new to SwiftUI and one thing I am struggling to understand is how do we call CoreData in ObservableObject?我是 SwiftUI 的新手,我很难理解的一件事是我们如何在 ObservableObject 中调用 CoreData?

I have the following code in place.我有以下代码。

SimpleTodoModel.xcdatamodeld Inside there is a simple entities name: Task SimpleTodoModel.xcdatamodeld 里面有一个简单的实体名称:Task

Main Application主要应用

import SwiftUI

@main
struct NewApp: App {
    
    let persistentContainer = CoreDataManager.shared.persistentContainer
    
    var body: some Scene {
        WindowGroup {
            ContentView().environment(\.managedObjectContext, persistentContainer.viewContext)
        }
    }
}

CoreDataManager and ContentView CoreDataManager 和 ContentView

import Foundation
import CoreData

class CoreDataManager {
    
    let persistentContainer: NSPersistentContainer
    static let shared: CoreDataManager = CoreDataManager()
    
    private init() {
        
        persistentContainer = NSPersistentContainer(name: "SimpleTodoModel")
        persistentContainer.loadPersistentStores { description, error in
            if let error = error {
                fatalError("Unable to initialize Core Data \(error)")
            }
        }
        
    }
    
}

struct ContentView: View {
    @EnvironmentObject var obs : observer
    @State private var title: String = ""
    @State private var selectedPriority: Priority = .medium
    @Environment(\.managedObjectContext) private var viewContext
    
    @FetchRequest(entity: Task.entity(), sortDescriptors: [NSSortDescriptor(key: "dateCreated", ascending: false)]) private var allTasks: FetchedResults<Task>
    
    private func saveTask() {
        
        do {
            let task = Task(context: viewContext)
            task.title = title
            task.priority = selectedPriority.rawValue
            task.dateCreated = Date()
            try viewContext.save()
        } catch {
            print(error.localizedDescription)
        }
        
    }

    var body: some View {
        NavigationView {
            VStack {
                   //making a view and calling coredata values which is working perfectly 
            }
        }
    }
}

Here is where i struggle, calling coredata outside of the view in a class/ObservableObject这是我挣扎的地方,在类/ObservableObject 的视图之外调用 coredata

class observer : ObservableObject{


     //How should i call the coredata instead? 
     //Say i want to change a piece of value in what i have saved above inside one of the Task record?


}

Presuming you want to do this with a strict MVVM architecture, here is a demonstration of how it may work for you.假设您想使用严格的 MVVM 架构来执行此操作,这里演示了它如何为您工作。 You will need a data model, and a view model.您将需要数据 model 和视图 model。

You data model essentially mimics the Core Data model:您的数据 model 本质上模仿了核心数据 model:

struct TaskModel: Identifiable {
    
    private var task: Task
    
    init(task: Task) {
        self.task = task
    }
    var id: NSManagedObjectID { // Identifiable conformance
        task.objectID
    }
    var dateCreated: Date {
        task.dateCreated
    }
    var priority: Priority {
        task.priority
    }
    var title: String {
        task.title
    }
}

extension TaskModel {
    init?(taskID: NSManagedObjectID, context: NSManagedObjectContext) {
        do {
            guard let task = try context.existingObject(with: taskID) as? Task else { return nil }
            self.task = task
        } catch {
            return nil
        }
    }
}

Your view model would then look something like this:您的视图 model 将如下所示:

@MainActor
class TaskListViewModel: NSObject, ObservableObject {
    
    @Published var tasks: [TaskModel] = []

    private let fetchResultsController: NSFetchedResultsController<Task>
    private let context: NSManagedObjectContext
    
    init(_ compoundPredicate: NSCompoundPredicate, category: CategoryModel? = nil, showTasks: ShowTasks, context: NSManagedObjectContext) {
        self.context = context
        let fetchRequest = Task.fetchRequest()
        
        super.init() // NSObject conformance to use the delegate
        fetchResultsController.delegate = self
        
        do {
            try fetchResultsController.performFetch()
            guard let tasks = fetchResultsController.fetchedObjects else { return }
            
            self.tasks = tasks.map(TaskModel.init)
        } catch {

        }
    }
    
    func deleteTask(_ task: TaskModel) {
        do {
            guard let taskObject = try context.existingObject(with: task.id) as? Task else { return }
            try taskObject.delete()
        } catch {

        }
    }

    func save(_ task: TaskModel) {
        do {
            guard let taskObject = try context.existingObject(with: task.id) as? Task else { return }
            try taskObject.save()
        } catch {

        }
    }    
}

The delegate will cause the view model to update when the Core Data model changes:当核心数据 model 更改时,委托将导致视图 model 更新:

extension TaskListViewModel: NSFetchedResultsControllerDelegate {
    func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
        guard let tasks = controller.fetchedObjects as? [Task] else { return }
        self.tasks = tasks.map(TaskModel.init)
    }
}

In your view, I would initialize it as a @StateObject , unless this is a common view model, in which case the first initialization should be as a @StateObject , and then injected appropriately, something like this:在你看来,我会把它初始化为@StateObject ,除非这是一个常见的视图 model,在这种情况下,第一次初始化应该是@StateObject ,然后适当地注入,就像这样:

@StateObject private var vm: TaskListViewModel
    
init(vm: TaskListViewModel) {
    _vm = StateObject(wrappedValue: vm)
}

This code has not been tested, so there may be some syntax errors...此代码尚未经过测试,因此可能存在一些语法错误......

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM