我想让我的 CoreData 同步到 iCloud,它现在工作得很好。但是当我在模拟器中关闭 iCloud 同步时,所有数据都会“丢失”。但当我再次打开 iCloud 同步时,数据会立即返回,这很好。但如果用户不想填满他的 iCloud 存储空间,我也希望数据能够存储在本地。
场景是:用户看到大量数据(永远不会是 GB 的数据,但也许有些用户即使有 MB 的数据也很挑剔)填满了他的 iCloud,并希望为我的应用程序关闭同步。当同步关闭时,所有用户的数据都会在本地消失,但仍在云端。我希望同步关闭时数据不会消失。
我的“要求”可以吗?
这是我的代码:
import CoreData
class DataController: ObservableObject {
lazy var persistentContainer: NSPersistentCloudKitContainer = {
let container = NSPersistentCloudKitContainer(name: "CoreData")
let address = Bundle.main.path(forResource: "CoreData", ofType: ".momd")
// Create a store description for a local store
let localStoreLocation = URL(fileURLWithPath: "\(address!)/Local.sqlite")
let localStoreDescription =
NSPersistentStoreDescription(url: localStoreLocation)
localStoreDescription.configuration = "Local"
// Create a store description for a CloudKit-backed local store
let cloudStoreLocation = URL(fileURLWithPath: "\(address!)/Cloud.sqlite")
let cloudStoreDescription =
NSPersistentStoreDescription(url: cloudStoreLocation)
cloudStoreDescription.configuration = "Cloud"
// Set the container options on the cloud store
cloudStoreDescription.cloudKitContainerOptions =
NSPersistentCloudKitContainerOptions(
containerIdentifier: "iCloud.com.my.identifier")
// Update the container's list of store descriptions
container.persistentStoreDescriptions = [
cloudStoreDescription,
localStoreDescription
]
// Load both stores
container.loadPersistentStores { storeDescription, error in
guard error == nil else {
fatalError("Could not load persistent stores. \(error!)")
}
}
return container
}()
init() {
persistentContainer.loadPersistentStores { description, error in
if let error = error {
print("Core Data failed to load: \(error.localizedDescription)")
}
}
persistentContainer.viewContext.automaticallyMergesChangesFromParent = true
}
}
您有两个持久存储描述,但这并不意味着当您保存一个对象时,它会进入两个持久存储。您的代码需要执行此操作。
一个托管对象只属于一个持久存储。如果您有多个商店(如您的代码中所示),会发生什么?由于您有多个持久存储,其中一个对象可能属于其中任何一个,因此它会进入列表中的第一个 - 这就是为什么它们在这里都是云对象。
如果您想在两个存储中保存相同的数据,则需要执行以下操作:
NSManagedObjectContext
的函数 assign(_ object: Any, to store: NSPersistentStore)
告诉它将重复项放入正确的存储中。NSFetchRequest
的属性 affectedStores
确保仅从两个存储之一获取。否则,您将获得重复的结果,因为您将获得来自两个商店的结果。由于重复项是不同的对象实例,因此它将具有不同的
NSManagedObjectID
。您可能需要添加自己的唯一 ID 字段,以便可以将一个商店中的对象与另一商店中的相应对象进行匹配。
每当更改托管对象时,您都需要执行类似的操作。如果您更改了一个,请从另一家商店找到重复的并进行相同的更改。
如果这听起来很复杂,确实如此。这不是一个简单的问题。这并非不可能,但要做好并不容易。
[如果您使用不同的模型配置,您可以将不同的托管对象类型放入特定的存储中。每个对象仍然会进入一个商店,而不是同时进入两个商店,但选择将是自动的。这无助于解决您的问题,但
assign
方法的文档提到了这种情况,所以我想我也会提到它。]