当 iCloud 同步关闭时,本地存储和 iCloud 中存储的 CoreData 会消失

问题描述 投票:0回答:1

我想让我的 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
    }
}
swift swiftui core-data icloud cloudkit
1个回答
3
投票

您有两个持久存储描述,但这并不意味着当您保存一个对象时,它会进入两个持久存储。您的代码需要执行此操作。

一个托管对象只属于一个持久存储。如果您有多个商店(如您的代码中所示),会发生什么?由于您有多个持久存储,其中一个对象可能属于其中任何一个,因此它会进入列表中的第一个 - 这就是为什么它们在这里都是云对象。

如果您想在两个存储中保存相同的数据,则需要执行以下操作:

  1. 每次创建新的托管对象时,请使用相同的数据进行复制。
  2. 使用
    NSManagedObjectContext
    的函数
    assign(_ object: Any, to store: NSPersistentStore)
    告诉它将重复项放入正确的存储中。
  3. 获取数据时,使用
    NSFetchRequest
    的属性
    affectedStores
    确保仅从两个存储之一获取。否则,您将获得重复的结果,因为您将获得来自两个商店的结果。

由于重复项是不同的对象实例,因此它将具有不同的

NSManagedObjectID
。您可能需要添加自己的唯一 ID 字段,以便可以将一个商店中的对象与另一商店中的相应对象进行匹配。

每当更改托管对象时,您都需要执行类似的操作。如果您更改了一个,请从另一家商店找到重复的并进行相同的更改。

如果这听起来很复杂,确实如此。这不是一个简单的问题。这并非不可能,但要做好并不容易。

[如果您使用不同的模型配置,您可以将不同的托管对象类型放入特定的存储中。每个对象仍然会进入一个商店,而不是同时进入两个商店,但选择将是自动的。这无助于解决您的问题,但

assign
方法的文档提到了这种情况,所以我想我也会提到它。]

© www.soinside.com 2019 - 2024. All rights reserved.