确实可以设置两个使用相同内存持久存储的核心数据堆栈,但它们并不是所有属性都作为SQLite存储。
以下是我对2个核心数据堆栈的测试设置:
let coreDataCloudKitContainer = CoreDataCloudKitContainer(name: appName, privateStoreType: .persistentStore)
// let coreDataCloudKitContainer = CoreDataCloudKitContainer(name: appName, privateStoreType: .nullDevice)
// let coreDataCloudKitContainer = CoreDataCloudKitContainer(name: appName, privateStoreType: .inMemory)
coreDataManager.persistentContainer = coreDataCloudKitContainer
let privateStore = coreDataCloudKitContainer.privateStore!
let mockStoreCoordinator = NSPersistentStoreCoordinator(managedObjectModel: CoreDataCloudKitContainer.managedObjectModel)
_ = try! mockStoreCoordinator.addPersistentStore(type: NSPersistentStore.StoreType(rawValue: privateStore.type),
configuration: privateStore.configurationName,
at: privateStore.url!,
options: [NSPersistentHistoryTrackingKey: true])
let viewContext = coreDataCloudKitContainer.viewContext
let mockViewContext = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
mockViewContext.persistentStoreCoordinator = mockStoreCoordinator
CoreDataCloudKitContainer
是的子类
NSPersistentCloudKitContainer
。它有一个静态
var managedObjectModel
在
init
的
CoreDataCloudKitContainer
以及
初始化
第2页
NSPersistentStoreCoordinator
(模型只能加载一次,否则核心数据会混淆):
static var managedObjectModel: NSManagedObjectModel = {
guard let modelFile = Bundle.main.url(forResource: appName, withExtension: "momd") else { fatalError("Canot find model file") }
guard let model = NSManagedObjectModel(contentsOf: modelFile) else { fatalError("Cannot parse model file") }
return model
}()
还要注意的是
addPersistentStore
使用选项
[NSPersistentHistoryTrackingKey: true]
如果
privateStore
定义为
privateStoreDescription.setOption(true as NSNumber, forKey: NSPersistentHistoryTrackingKey)
。如果未设置,则会出现错误
CoreData: fault: Store opened without NSPersistentHistoryTrackingKey but previously had been opened with NSPersistentHistoryTrackingKey - Forcing into Read Only mode store at 'file://...
privateStore
初始化为
let privateStoreURL: URL
switch privateStoreType {
case .persistentStore:
privateStoreURL = CoreDataCloudKitContainer.appDefaultDirectoryURL.appendingPathComponent("Private.sqlite")
case .nullDevice, .inMemory:
privateStoreURL = URL(fileURLWithPath: "/dev/null")
}
print("privateStoreURL: \(privateStoreURL)")
let privateStoreDescription = NSPersistentStoreDescription(url: privateStoreURL)
privateStoreDescription.url = privateStoreURL
privateStoreDescription.configuration = privateConfigurationName
privateStoreDescription.timeout = timeout
privateStoreDescription.type = type
privateStoreDescription.isReadOnly = isReadOnly
privateStoreDescription.shouldAddStoreAsynchronously = shouldAddStoreAsynchronously
privateStoreDescription.shouldInferMappingModelAutomatically = shouldInferMappingModelAutomatically
privateStoreDescription.shouldMigrateStoreAutomatically = shouldMigrateStoreAutomatically
// The options below have to be set before loadPersistentStores
// Enable history tracking and remote notifications
privateStoreDescription.setOption(true as NSNumber, forKey: NSPersistentHistoryTrackingKey)
privateStoreDescription.setOption(true as NSNumber, forKey: NSPersistentStoreRemoteChangeNotificationPostOptionKey)
if isTesting {
privateStoreDescription.cloudKitContainerOptions = nil
} else {
privateStoreDescription.cloudKitContainerOptions = NSPersistentCloudKitContainerOptions(containerIdentifier: kICloudContainerID)
privateStoreDescription.cloudKitContainerOptions!.databaseScope = .private
}
其中类型为
NSSQLiteStoreType
对于
privateStoreType == .persistentStore
和
.nullDevice
和
NSInMemoryStoreType
对于
privateStoreType == .inMemory
。请注意,选项
.nullDevice
仅在内存中创建SQLite存储,但是
.inMemory
创建
一些
存储在内存中,但它是
不
SQLite存储。关于
.nullDevice
可以在中找到商店
this blog
。
警告:
尽管可以使用相同的内存中持久存储设置2个核心数据堆栈,但这种存储有局限性。一个是通过一个堆栈修改存储不会触发
NSPersistentStoreRemoteChangeNotification
,因此无法对iCloud镜像进行单元测试。为此,必须使用基于文件的SQLite持久存储。