9

我突然在 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'.
4

3 回答 3

8

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

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

[更新]

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

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 扩展中使用计算属性:

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

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

于 2018-10-22T04:25:59.683 回答
1

我想出了如何解决这个问题。您必须在单元测试类中创建一个 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)
   }
于 2019-05-23T05:44:22.817 回答
0

如果每次你想访问你的持久化容器你创建一个 NSPersistentContainer(name:) 的实例,你会得到这个警告。我遇到了这个问题,因为我在存储类中使用了两个不同的容器(每个容器用于不同的托管对象模型)。我通过将每个容器保存在 var 属性中来解决它,并且每当我更改持久性容器时,我都会从属性中重新分配它,而不像这样创建另一个实例:

var mainPersistentContainer: NSPersistentContainer?
var firstContainer : NSPersistentContainer?
var secondContainer: NSPersistentContainer?

然后当你初始化容器时尝试将它分配给你的变量

if firstContainerCondition {
if firstContainer != nil {
mainPersistentContainer = firstContainer
} else {
firstContainer = NSPersistentContainer(name: "firstMangedObjectModel")
}

第二个容器也是如此。

于 2020-10-20T16:17:57.767 回答