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

Dun*_*ald 5 core-data nsmanagedobjectmodel ios12

我突然在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'.
Run Code Online (Sandbox Code Playgroud)

小智 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
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

var container : persistentContainer { return DateCtrl.shared.container }
Run Code Online (Sandbox Code Playgroud)

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


And*_*lva 5

当我实例化一个新的 NSManagedObject 子类时,发生了这种情况,如下所示:

let newItem = Item(context: myContext)
Run Code Online (Sandbox Code Playgroud)

2022 年对我来说最有效的是创建一个扩展:

extension NSManagedObject {
    
    convenience init(context: NSManagedObjectContext) {
        let name = String(describing: type(of: self))
        let entity = NSEntityDescription.entity(forEntityName: name, in: context)!
        self.init(entity: entity, insertInto: context)
    }
}
Run Code Online (Sandbox Code Playgroud)

通过此扩展,我不再收到警告,因为我正在从实体描述初始化托管对象。根据Apple 的文档,扩展init(entity: NSEntityDescription, insertInto context: NSManagedObjectContext?)中使用的方法是 NSManagedObject 的指定初始值设定项。

“NSManagedObject 使用动态类生成来支持 Objective-C 2 属性功能(请参阅声明的属性),方法是自动创建适合实体的类的子类。initWithEntity:insertIntoManagedObjectContext:因此返回适合实体的类的实例。动态-生成的子类将基于实体指定的类,因此在模型中指定自定义类将取代传递给 alloc 的类。”