我突然在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'.
答案 0 :(得分:1)
我刚刚解决了我对持久性容器使用计算属性的相同错误。因此,每次应用访问持久性容器/存储时,都会从磁盘创建新的数据模型实例。
将持久性容器更改为惰性存储属性后,问题消失了。
[更新]
当前,我为核心数据堆栈使用一个单独的类,其中使用了如下所示的单例:
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()来控制加载第一个视图控制器的数据模型。
答案 1 :(得分:0)
我想出了解决方法。您必须在单元测试类中创建一个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)
}
答案 2 :(得分: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")
}
第二个容器也是如此。