SwiftUI 和单元测试失败:使用核心数据堆栈时无法添加相同的商店两次
SwiftUI & Unit test fails: Can't add the same store twice when using core data stack
将 Xcode 更新到 13.4 后,我的核心数据持久性堆栈开始无法用于 SwiftUI 预览和 Xcode 单元测试。
错误信息:
Unresolved error Error Domain=NSCocoaErrorDomain Code=134081 "(null)" UserInfo={NSUnderlyingException=Can't add the same store twice}, ["NSUnderlyingException": Can't add the same store twice ...
持久性堆栈:
struct PersistenceController {
static let shared = PersistenceController()
let container: NSPersistentContainer
init(inMemory: Bool = false) {
container = NSPersistentContainer(name: "Persistence")
if inMemory {
container.persistentStoreDescriptions.first!.url = URL(fileURLWithPath: "/dev/null")
}
let description = NSPersistentStoreDescription()
description.shouldInferMappingModelAutomatically = true
description.shouldMigrateStoreAutomatically = true
container.persistentStoreDescriptions.append(description)
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
container.viewContext.automaticallyMergesChangesFromParent = true
}
}
SwiftUI 预览的用法:
struct MyScreen_Previews: PreviewProvider {
static var previews: some View {
MyScreen()
.environment(\.managedObjectContext, PersistenceController.preview.container.viewContext)
}
}
支持 SwiftUI 预览的扩展:
extension PersistenceController {
static var preview: PersistenceController = {
let result = PersistenceController(inMemory: true)
// Pre-fill core data with required information for preview.
}
}
我注意到,在加载持久性存储后生成了错误。此错误(无法添加同一商店两次),对于 SwiftUI 预览和单元测试可以忽略。
要忽略此类错误需要检查进程信息中的 XCTestSessionIdentifier 和 XCODE_RUNNING_FOR_PREVIEWS。
if let error = error as NSError? {
if ProcessInfo.processInfo.environment["XCTestSessionIdentifier"] == nil &&
ProcessInfo.processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] == nil {
fatalError("Unresolved error \(error), \(error.userInfo)")
}
}
您的代码中有一个错误,当您附加到描述数组时,您现在有 2 个描述。
改为:
let description = container.persistentStoreDescriptions.first!
description.shouldInferMappingModelAutomatically = true
description.shouldMigrateStoreAutomatically = true
// Load
将 Xcode 更新到 13.4 后,我的核心数据持久性堆栈开始无法用于 SwiftUI 预览和 Xcode 单元测试。
错误信息:
Unresolved error Error Domain=NSCocoaErrorDomain Code=134081 "(null)" UserInfo={NSUnderlyingException=Can't add the same store twice}, ["NSUnderlyingException": Can't add the same store twice ...
持久性堆栈:
struct PersistenceController {
static let shared = PersistenceController()
let container: NSPersistentContainer
init(inMemory: Bool = false) {
container = NSPersistentContainer(name: "Persistence")
if inMemory {
container.persistentStoreDescriptions.first!.url = URL(fileURLWithPath: "/dev/null")
}
let description = NSPersistentStoreDescription()
description.shouldInferMappingModelAutomatically = true
description.shouldMigrateStoreAutomatically = true
container.persistentStoreDescriptions.append(description)
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
container.viewContext.automaticallyMergesChangesFromParent = true
}
}
SwiftUI 预览的用法:
struct MyScreen_Previews: PreviewProvider {
static var previews: some View {
MyScreen()
.environment(\.managedObjectContext, PersistenceController.preview.container.viewContext)
}
}
支持 SwiftUI 预览的扩展:
extension PersistenceController {
static var preview: PersistenceController = {
let result = PersistenceController(inMemory: true)
// Pre-fill core data with required information for preview.
}
}
我注意到,在加载持久性存储后生成了错误。此错误(无法添加同一商店两次),对于 SwiftUI 预览和单元测试可以忽略。
要忽略此类错误需要检查进程信息中的 XCTestSessionIdentifier 和 XCODE_RUNNING_FOR_PREVIEWS。
if let error = error as NSError? {
if ProcessInfo.processInfo.environment["XCTestSessionIdentifier"] == nil &&
ProcessInfo.processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] == nil {
fatalError("Unresolved error \(error), \(error.userInfo)")
}
}
您的代码中有一个错误,当您附加到描述数组时,您现在有 2 个描述。
改为:
let description = container.persistentStoreDescriptions.first!
description.shouldInferMappingModelAutomatically = true
description.shouldMigrateStoreAutomatically = true
// Load