代码之家  ›  专栏  ›  技术社区  ›  Duncan Groenewald

CoreData警告:多个NSEntityDescriptions声明NSManagedObject子类

  •  4
  • Duncan Groenewald  · 技术社区  · 7 年前

    我突然在iOS12/XCode 9上收到一堆警告。为什么有多个managedObjectModels?应用程序只有一个*.xcdatamodeld文件,但模型中有多个版本。

    这是一个新的iOS12 Coredata特性吗?我可以做些什么来防止这个警告,还是应该忽略它?

    2018-09-18 11:45:34.487073+1000 xxxxxxxxx[4422:1419983] [error] warning:     'Stats' (0x2812f1550) from NSManagedObjectModel (0x2806ff480) claims 'Stats'.
    CoreData: warning:       'Stats' (0x2812f1550) from NSManagedObjectModel (0x2806ff480) claims 'Stats'.
    2018-09-18 11:45:34.487084+1000 xxxxxxxxx[4422:1419983] [error] warning:     'Stats' (0x2812f3bd0) from NSManagedObjectModel (0x2806b18b0) claims 'Stats'.
    CoreData: warning:       'Stats' (0x2812f3bd0) from NSManagedObjectModel (0x2806b18b0) claims 'Stats'.
    
    1 回复  |  直到 7 年前
        1
  •  3
  •   Ron Liu    6 年前

    我刚刚解决了同一个错误,即我对持久化容器使用了computed属性。因此,每次应用程序访问持久容器/存储时,都会从磁盘创建新的数据模型实例。

    在我将persistent容器更改为惰性存储属性之后,问题就消失了。

    [更新]

    目前,我为核心数据堆栈使用一个单独的类,其中使用了如下单例:

    class DataCtrl : NSObject {
    
    static shared = DateCtrl()
    var container: NSPersistentContainer?
    
    private override init() { 
        container = NSPersistentContainer(name: "dataModelName")
    }
    func loadStore (completionHandler: @escaping () -> ()) {
    self.container?.loadPersisentStores() { 
    desc, err in ...
        completionHandler
        }
     }
    }
    

    然后我可以轻松地在tableViewController扩展中使用computed属性:

    var container : persistentContainer { return DateCtrl.shared.container }
    

    当然,您需要调用AppDelegate didffinishlaunchingwithoptions块中的func load store首先加载持久存储,在completionHandler中使用DispatchGroup()来控制加载第一个视图控制器的数据模型。

        2
  •  0
  •   Diviyo    6 年前

    我想出了解决办法。必须在单元测试类中创建一个NSEntityDescription实例,并在每次创建与实体描述匹配的对象时重用它。在下面的代码中,查看setup、tearDown和testFetchPerson()

       var container: NSPersistentContainer!
    
       **var entityDescription: NSEntityDescription! // Insert only one instance into your managed object context * see setup//**
    
       override func setUp() {
           super.setUp()
           let bundle = Bundle(for: type(of: self))
           let url = bundle.url(forResource: "DivyaPracticeWorkspace", withExtension: "momd")!
           let managedObjectModel = NSManagedObjectModel(contentsOf: url)!
           container = NSPersistentContainer(name: "testContainer", managedObjectModel: managedObjectModel)
           let description = NSPersistentStoreDescription()
           description.type = NSInMemoryStoreType
           container.persistentStoreDescriptions = [description]
           container.loadPersistentStores(completionHandler: { (description, error) in
               if let error = error {
                   print("\(error)")
               }
           })
    
           mockCoreData = CoreDataManager(container: container)
    **// Insert only one entity description into the context
           entityDescription  = NSEntityDescription.entity(forEntityName: "Person", in: mockCoreData.mainContext)!**
       }
    
    
       override func tearDown() {
           super.tearDown()
           deleteAllObjects()
           mockCoreData = nil
           container = nil
       }
    
       private func deleteAllObjects() {
           let request: NSFetchRequest<Person> = Person.fetchRequest()
           do {
               let results = try mockCoreData.mainContext.fetch(request)
               for entry in results {
                   mockCoreData.mainContext.delete(entry)
               }
    
               mockCoreData.saveChanges {
                   [weak self] in
                   guard let this = self else {
                       return
                   }
    
                   this.mockCoreData.mainContext.refreshAllObjects()
                   this.mockCoreData.mainContext.reset()
                   guard let store = this.container.persistentStoreCoordinator.persistentStores.first else {
                       return
                   }
                   do {
                       try this.container.persistentStoreCoordinator.remove(store)
                   } catch let error {
                       print("\(error)")
                   }
               }
           } catch let error {
               print("\(error)")
           }
       }
    
       func testFetchPerson() {
            var fetchSuccess = false
    **// Create person entity using the entity description created in setup.
               let personEntity = Person(entity: entityDescription, insertInto: mockCoreData.mainContext)**
    
               personEntity.name = "Bob"
               personEntity.gender = Int32(0)
    
               mockCoreData.saveChanges(completion: nil)
    
    
               if let personFetched = mockCoreData.fetchPerson(name: "Bob")?.first {
                   fetchSuccess = personFetched.gender == Int32(0) && personFetched.name == "Bob"
               }
           XCTAssertTrue(fetchSuccess)
       }
    
    推荐文章