Core data 多个NSEntityDescriptions声明NSManagedObject子类

Core data 多个NSEntityDescriptions声明NSManagedObject子类,core-data,nsmanagedobject,nsmanagedobjectcontext,Core Data,Nsmanagedobject,Nsmanagedobjectcontext,我正在创建一个允许我使用核心数据的框架。在框架的测试目标中,我配置了一个名为MockModel.xcdatamodeld的数据模型。它包含一个名为MockManaged的实体,该实体具有一个Date属性 为了测试我的逻辑,我正在创建一个内存存储。当我想验证我的保存逻辑时,我会创建一个内存中存储的实例并使用它。但是,我在控制台中不断获得以下输出: 2018-08-14 20:35:45.340157-0400 xctest[7529:822360][错误]警告:多个NSEntityDescript

我正在创建一个允许我使用核心数据的框架。在框架的测试目标中,我配置了一个名为
MockModel.xcdatamodeld
的数据模型。它包含一个名为
MockManaged
的实体,该实体具有一个
Date
属性

为了测试我的逻辑,我正在创建一个内存存储。当我想验证我的保存逻辑时,我会创建一个内存中存储的实例并使用它。但是,我在控制台中不断获得以下输出:

2018-08-14 20:35:45.340157-0400 xctest[7529:822360][错误]警告:多个NSEntityDescriptions声明NSManagedObject子类“LocalPersistenceTests.MockManaged”so+实体无法消除歧义。
CoreData:警告:多个NSEntityDescriptions声明NSManagedObject子类“LocalPersistenceTests.MockManaged”so+实体无法消除歧义。
2018-08-14 20:35:45.340558-0400 xctest[7529:822360][错误]警告:来自NSManagedObjectModel(0x7f9868604090)的“MockManaged”(0x7f986861cae0)声明“LocalPersistenceTests.MockManaged”。
CoreData:警告:NSManagedObjectModel(0x7f9868604090)中的“MockManaged”(0x7f986861cae0)声明“LocalPersistenceTests.MockManaged”。
2018-08-14 20:35:45.340667-0400 xctest[7529:822360][错误]警告:来自NSManagedObjectModel(0x7f9868418ee0)的“MockManaged”(0x7f986acc4d10)声明“LocalPersistenceTests.MockManaged”。
CoreData:警告:NSManagedObjectModel(0x7f9868418ee0)中的“MockManaged”(0x7f986acc4d10)声明“LocalPersistenceTests.MockManaged”。
2018-08-14 20:35:45.342938-0400 XTest[7529:822360][error]错误:+[LocalPersistenceTests.MockManaged entity]未能找到NSEntityDescription与托管对象子类的唯一匹配项
CoreData:错误:+[LocalPersistenceTests.MockManaged entity]未能找到NSEntityDescription与托管对象子类的唯一匹配项
下面是我用来创建内存存储的对象:

类MockNSManagedObjectContextCreator{
//标记:-NSManagedObjectContext创建
静态函数inMemoryContext()->NSManagedObjectContext{
guard let model=NSManagedObjectModel.mergedModel(来自:[Bundle(for:self)])else{fatalError(“无法创建模型”)}
let coordinator=NSPersistentStoreCoordinator(managedObjectModel:model)
做{
尝试coordinator.addPersistentStore(ofType:NSInMemoryStoreType,configurationName:nil,at:nil,options:nil)
}抓住{
fatalError(“无法创建内存存储”)
}
let context=NSManagedObjectContext(并发类型:.mainQueueConcurrencyType)
context.persistentstorecomporator=协调器
返回上下文
}
}
下面是我的
MockManaged
实体的组成部分:

类MockManaged:NSManagedObject,托管{
//标记:-属性
@NSVAR管理日期:日期
}
下面是我的
XCTestCase
的组成部分:

类测试\n管理对象上下文:XCTestCase{
//标记:-对象插入
func测试\u NSManagedObjectContext\u InsertsManagedObject\u当对象符合ManagedProtocol()时{
让context=MockNSManagedObjectContextCreator.inMemoryContext()
let changeExpectation=期望值(用于通知:.nsManagedObjectContextObjectsIDChange,对象:上下文,处理程序:nil)
let对象:MockManaged=context.insertObject()
object.date=日期()
等待(等待:[ChangeExpection],超时:2)
}
//马克:节省
func test\u NSManagedObjectContext\u在更改时保存{
让context=MockNSManagedObjectContextCreator.inMemoryContext()
让saveExpectation=expectation(用于通知:.NSManagedObjectContextDidSave,对象:上下文,处理程序:nil)
let对象:MockManaged=context.insertObject()
object.date=日期()
做{
尝试context.saveIfHasChanges()
}抓住{
XCTFail(“预期成功保存”)
}
等待(等待:[SaveExpection],超时:2)
}
func测试\u NSManagedObjectContext \u在未更改ShaveBeenMade()时不保存{
让context=MockNSManagedObjectContextCreator.inMemoryContext()
让saveExpectation=expectation(用于通知:.NSManagedObjectContextDidSave,对象:上下文,处理程序:nil)
saveExpection.isInverted=true
做{
尝试context.saveIfHasChanges()
}抓住{
XCTFail(“意外错误:\(错误)”)
}
等待(等待:[SaveExpection],超时:2)
}
}
我在做什么导致测试中出现错误?

自动缓存后 对于
nspersist[CloudKit]容器(名称:String)
,这种情况不应该再发生了,因为它现在似乎会自动缓存模型(Swift 5.1、Xcode11、iOS13/MacOS10.15)

预自动缓存
NSPersistentContainer/NSPersistentCloudKitContainer
有两个构造函数:

第一个只是一个方便的初始化器,使用从磁盘加载的模型调用第二个。问题在于,从同一
app/test调用中的磁盘加载同一
NSManagedObjectModel
两次会导致上述错误,因为每次加载模型都会导致外部注册调用,这会在同一
app/test调用中打印第二次调用的错误。
而
init(名称:String)
不够聪明,无法缓存模型

因此,如果要多次加载容器,则必须加载一次
NSManagedObjectModel
,并将其存储在一个属性中,然后在每次
init(名称:managedObjectModel:)
调用中使用该属性

示例:缓存模型 旧答案 加载核心数据有点神奇,从磁盘加载一个模型并使用它意味着它注册了某些类型。阿瑟
import Foundation
import SwiftUI
import CoreData
import CloudKit

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 CoreDataError.modelURLNotFound(forResourceName: name)
        }

        guard let model = NSManagedObjectModel(contentsOf: modelURL) else {
            throw CoreDataError.modelLoadingFailed(forURL: modelURL)
       }
        return model
    }

    enum CoreDataError: Error {
        case modelURLNotFound(forResourceName: String)
        case modelLoadingFailed(forURL: URL)
    }

    public static func container() throws -> NSPersistentCloudKitContainer {
        let name = "ItmeStore"
        return NSPersistentCloudKitContainer(name: name, managedObjectModel: try model(name: name))
    }
}
import CoreData

public extension NSManagedObject {

    convenience init(usedContext: NSManagedObjectContext) {
        let name = String(describing: type(of: self))
        let entity = NSEntityDescription.entity(forEntityName: name, in: usedContext)!
        self.init(entity: entity, insertInto: usedContext)
    }

}
class UnitTestBase {
    static let managedObjectModel: NSManagedObjectModel = {
        let managedObjectModel = NSManagedObjectModel.mergedModel(from: [Bundle(for: UnitTestBase.self)])!
        return managedObjectModel
    }()


    override func setUp() {
        // setup in-memory NSPersistentContainer
        let storeURL = NSPersistentContainer.defaultDirectoryURL().appendingPathComponent("store")
        let description = NSPersistentStoreDescription(url: storeURL)
        description.shouldMigrateStoreAutomatically = true
        description.shouldInferMappingModelAutomatically = true
        description.shouldAddStoreAsynchronously = false
        description.type = NSInMemoryStoreType

        let persistentContainer = NSPersistentContainer(name: "DataModel", managedObjectModel: UnitTestBase.managedObjectModel)
        persistentContainer.persistentStoreDescriptions = [description]
        persistentContainer.loadPersistentStores { _, error in
            if let error = error {
                fatalError("Fail to create CoreData Stack \(error.localizedDescription)")
            } else {
                DDLogInfo("CoreData Stack set up with in-memory store type")
            }
        }

        inMemoryPersistentContainer = persistentContainer
    }
}
struct ManagedObjectModels {

   static let main: NSManagedObjectModel = {
       return buildModel(named: "main")
   }()

   static let cache: NSManagedObjectModel = {
       return buildModel(named: "cache")
   }()

   private static func buildModel(named: String) -> NSManagedObjectModel {
       let url = Bundle.main.url(forResource: named, withExtension: "momd")!
       let managedObjectModel = NSManagedObjectModel.init(contentsOf: url)
       return managedObjectModel!
   }
}
let container = NSPersistentContainer(name: "cache", managedObjectModel: ManagedObjectModels.cache)
class CoreDataStack {

    static let shared = CoreDataStack()

    private init() {}

    var managedContext: NSManagedObjectContext {
        return self.storeContainer.viewContext
    }

//...
}
class PersistenceManager {
    let storeName: String!

   static var managedObjectModel: NSManagedObjectModel = {
            let managedObjectModel = NSManagedObjectModel.mergedModel(from: [Bundle(for: PersistenceManager.self)])!
            return managedObjectModel
        }()

    ...
}
lazy var inMemoryContainer: NSPersistentContainer = {
    // Reference the model inside the app, rather than loading it again, to prevent duplicate errors
    let container = NSPersistentContainer(name: "TestContainer", managedObjectModel: PersistenceManager.managedObjectModel)
    let description = NSPersistentStoreDescription()
    description.type = NSInMemoryStoreType
    description.shouldAddStoreAsynchronously = false

    container.persistentStoreDescriptions = [description]
    container.loadPersistentStores { (description, error) in
        precondition(description.type == NSInMemoryStoreType)
        if let error = error {
            fatalError("Create an in-memory coordinator failed \(error)")
        }
    }
    return container
}()
NSBatchInsertRequest(entityName: entityNameAlert(), objects: ...) //<- entityNameAlert() is a method that returns my entity name as a string
NSBatchInsertRequest(entity: Alert.entity(), objects: ...)