这是一个完整的工作示例,当CloudKit使用CoreData++发生变化时更新CloudKitUI MVVM。与通知相关的代码标有注释、查看 CoreDataManager和SwiftUI文件。不要忘记在 Xcode 中添加适当的功能,请参见下图。
持久性/数据管理器
import CoreData
import SwiftUI
class CoreDataManager{
static let instance = CoreDataManager()
let container: NSPersistentCloudKitContainer
let context: NSManagedObjectContext
init(){
container = NSPersistentCloudKitContainer(name: "CoreDataContainer")
guard let description = container.persistentStoreDescriptions.first else{
fatalError("###\(#function): Failed to retrieve a persistent store description.")
}
description.setOption(true as NSNumber, forKey: NSPersistentHistoryTrackingKey)
// Generate NOTIFICATIONS on remote changes
description.setOption(true as NSNumber, forKey: NSPersistentStoreRemoteChangeNotificationPostOptionKey)
container.loadPersistentStores { (description, error) in
if let error = error{
print("Error loading Core Data. \(error)")
}
}
container.viewContext.automaticallyMergesChangesFromParent = true
container.viewContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
context = container.viewContext
}
func save(){
do{
try context.save()
print("Saved successfully!")
}catch let error{
print("Error saving Core Data. \(error.localizedDescription)")
}
}
}
查看模型
import CoreData
class CarViewModel: ObservableObject{
let manager = CoreDataManager.instance
@Published var cars: [Car] = []
init(){
getCars()
}
func addCar(model:String, make:String?){
let car = Car(context: manager.context)
car.make = make
car.model = model
save()
getCars()
}
func getCars(){
let request = NSFetchRequest<Car>(entityName: "Car")
let sort = NSSortDescriptor(keyPath: \Car.model, ascending: true)
request.sortDescriptors = [sort]
do{
cars = try manager.context.fetch(request)
}catch let error{
print("Error fetching cars. \(error.localizedDescription)")
}
}
func deleteCar(car: Car){
manager.context.delete(car)
save()
getCars()
}
func save(){
self.manager.save()
}
}
SwiftUI
import SwiftUI
import CoreData
struct ContentView: View {
@StateObject var carViewModel = CarViewModel()
@State private var makeInput:String = ""
@State private var modelInput:String = ""
// Capture NOTIFICATION changes
var didRemoteChange = NotificationCenter.default.publisher(for: .NSPersistentStoreRemoteChange).receive(on: RunLoop.main)
@State private var deleteCar: Car?
var body: some View {
NavigationView {
VStack{
List {
if carViewModel.cars.isEmpty {
Text("No cars")
.foregroundColor(.gray)
.fontWeight(.light)
}
ForEach(carViewModel.cars) { car in
HStack{
Text(car.model ?? "Model")
Text(car.make ?? "Make")
.foregroundColor(Color(UIColor.systemGray2))
}
.swipeActions{
Button( role: .destructive){
carViewModel.deleteCar(car: car)
}label:{
Label("Delete", systemImage: "trash.fill")
}
}
}
}
// Do something on NOTIFICATION
.onReceive(self.didRemoteChange){ _ in
carViewModel.getCars()
}
Spacer()
Form {
TextField("Make", text:$makeInput)
TextField("Model", text:$modelInput)
}
.frame( height: 200)
Button{
saveNewCar()
makeInput = ""
modelInput = ""
}label: {
Image(systemName: "car")
Text("Add Car")
}
.padding(.bottom)
}
}
}
func saveNewCar(){
if !modelInput.isEmpty{
carViewModel.addCar(model: modelInput, make: makeInput.isEmpty ? nil : makeInput)
}
}
}
核心数据容器
实体
Car
属性
制作String
模型String
Xcode/CloudKit 设置

感谢Didier B.来自这个线程。