[英]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.