ios - CoreData+CloudKit | 开/关 iCloud 同步切换
问题描述
我想让用户选择打开和关闭 iCloud 同步。
经过一段时间的研究,我发现实现这一目标的一种方法是设置cloudKitContainerOptions
.
因此,nil
如果我不想同步我的数据库,我会将其设置为。
if(!UserDefaultsManager.shared.iCloudSyncOn) {
description.cloudKitContainerOptions = nil
}
这一切都很好,但我还没有找到在运行时做到这一点的方法。
我试图在用户切换时重新初始化我的容器,以便我的容器cloudKitContainerOptions
根据选择而有所不同。
但这只会在保存上下文时返回一个错误,说:Thread 1: "Illegal attempt to establish a relationship 'addEntries' between objects in different contexts ...
,我认为这是由于重新初始化。
我想我必须将新创建的上下文传递给我的整个视图层次结构,任何缓存 moc 的东西?
这是我的 CoreDataStack 的简化片段:
func setupContainer() -> NSPersistentContainer {
let container = NSPersistentCloudKitContainer(name: "...")
guard let description = container.persistentStoreDescriptions.first else { ... }
...
if(!UserDefaultsManager.shared.iCloudSyncOn) {
description.cloudKitContainerOptions = nil
}
container.loadPersistentStores(completionHandler: { ... })
...
return container
}
当用户切换时,setupContainer()
被调用。
任何帮助都会很棒,当然也欢迎替代方法!
谢谢。
解决方案
我已经能够让它工作了!
我的问题特别是在重新初始化persistenceContainer(创建了一个新的上下文)之后,我没有更新我已经获取的对象(使用旧的上下文)。
因此,直接在调用之后setupContainer()
,对我的所有对象进行简单的获取(使用新上下文)就足够了。
self.container = setupContainer()
CoreDataManager.shared.fetchAllItem()
附加内容
由于重新初始化,我又遇到了一个问题,这是一个警告,多个NSEntityDescriptions
正在声明NSManagedObject Subclass
我的实体。
这个答案为我解决了这个问题。
最终代码
也许这可以帮助你。对我来说很好。(iOS 14.2) 稍作修改。
PS:我没有设置,而是在和cloudKitContainerOptions
之间切换。NSPersistentCloudKitContainer
NSPersistenttContainer
lazy var container: NSPersistentContainer = {
setupContainer()
}()
func updateContainer() {
saveContext()
container = setupContainer()
CoreDataManager.shared.fetchAllItems()
}
private func setupContainer() -> NSPersistentContainer {
let iCloud = UserDefaultsManager.shared.settingICloudSynch
do {
let newContainer = try PersistentContainer.getContainer(iCloud: iCloud)
guard let description = newContainer.persistentStoreDescriptions.first else { fatalError("No description found") }
if iCloud {
newContainer.viewContext.automaticallyMergesChangesFromParent = true
newContainer.viewContext.mergePolicy = NSMergeByPropertyStoreTrumpMergePolicy
} else {
description.setOption(true as NSNumber, forKey: NSPersistentHistoryTrackingKey)
}
description.setOption(true as NSNumber, forKey: NSPersistentStoreRemoteChangeNotificationPostOptionKey)
newContainer.loadPersistentStores { (storeDescription, error) in
if let error = error as NSError? { fatalError("Unresolved error \(error), \(error.userInfo)") }
}
return newContainer
} catch {
print(error)
}
fatalError("Could not setup Container")
}
final class PersistentContainer {
private static var _model: NSManagedObjectModel?
private static func model(name: String) throws -> NSManagedObjectModel {
if _model == nil {
_model = try loadModel(name: name, bundle: Bundle.main)
}
return _model!
}
private static func loadModel(name: String, bundle: Bundle) throws -> NSManagedObjectModel {
guard let modelURL = bundle.url(forResource: name, withExtension: "momd") else {
throw CoreDataModelError.modelURLNotFound(forResourceName: name)
}
guard let model = NSManagedObjectModel(contentsOf: modelURL) else {
throw CoreDataModelError.modelLoadingFailed(forURL: modelURL)
}
return model
}
enum CoreDataModelError: Error {
case modelURLNotFound(forResourceName: String)
case modelLoadingFailed(forURL: URL)
}
public static func getContainer(iCloud: Bool) throws -> NSPersistentContainer {
let name = "YOUR APP"
if iCloud {
return NSPersistentCloudKitContainer(name: name, managedObjectModel: try model(name: name))
} else {
return NSPersistentContainer(name: name, managedObjectModel: try model(name: name))
}
}
}
推荐阅读
- python - 如何使用雅虎!来自 Julia 的金融市场数据下载器(yfinance)Python 包?
- java - 单击框生成数字时如何使用 ActionListener 事件?
- symfony - 清除 Symfony 项目的缓存是否安全
- javascript - 为什么没有在控制台中打印数组括号?
- angular - 为Angular中的所有HTTP请求添加参数
- javascript - 带有 async/await 的递归 setTimeout
- python-3.x - 如何在不同的起始索引而不是[0]处为列表启动for循环?
- angular - Angular Jasmine 测试:使用 setTimeout 时,SPEC 没有任何期望
- filemaker - 如何从文件制作器中的门户行打印
- c - 在结构中按频率对数组中的字母进行排序