多个 NSEntityDescription 声明 NSManagedObject 子类

2024-04-17

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

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

2018-08-14 20:35:45.340157-0400 xctest[7529:822360] [error] warning: Multiple NSEntityDescriptions claim the NSManagedObject subclass 'LocalPersistenceTests.MockManaged' so +entity is unable to disambiguate.
CoreData: warning: Multiple NSEntityDescriptions claim the NSManagedObject subclass 'LocalPersistenceTests.MockManaged' so +entity is unable to disambiguate.
2018-08-14 20:35:45.340558-0400 xctest[7529:822360] [error] warning:     'MockManaged' (0x7f986861cae0) from NSManagedObjectModel (0x7f9868604090) claims 'LocalPersistenceTests.MockManaged'.
CoreData: warning:       'MockManaged' (0x7f986861cae0) from NSManagedObjectModel (0x7f9868604090) claims 'LocalPersistenceTests.MockManaged'.
2018-08-14 20:35:45.340667-0400 xctest[7529:822360] [error] warning:     'MockManaged' (0x7f986acc4d10) from NSManagedObjectModel (0x7f9868418ee0) claims 'LocalPersistenceTests.MockManaged'.
CoreData: warning:       'MockManaged' (0x7f986acc4d10) from NSManagedObjectModel (0x7f9868418ee0) claims 'LocalPersistenceTests.MockManaged'.
2018-08-14 20:35:45.342938-0400 xctest[7529:822360] [error] error: +[LocalPersistenceTests.MockManaged entity] Failed to find a unique match for an NSEntityDescription to a managed object subclass
CoreData: error: +[LocalPersistenceTests.MockManaged entity] Failed to find a unique match for an NSEntityDescription to a managed object subclass

下面是我用来创建内存存储的对象:

class MockNSManagedObjectContextCreator {

    // MARK: - NSManagedObjectContext Creation

    static func inMemoryContext() -> NSManagedObjectContext {
        guard let model = NSManagedObjectModel.mergedModel(from: [Bundle(for: self)]) else { fatalError("Could not create model") }
        let coordinator = NSPersistentStoreCoordinator(managedObjectModel: model)
        do {
            try coordinator.addPersistentStore(ofType: NSInMemoryStoreType, configurationName: nil, at: nil, options: nil)
        } catch {
            fatalError("Could not create in-memory store")
        }
        let context = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
        context.persistentStoreCoordinator = coordinator
        return context
    }

}

下面是我的构成MockManaged entity:

class MockManaged: NSManagedObject, Managed {

    // MARK: - Properties

    @NSManaged var date: Date

}

下面是我的构成XCTestCase:

class Tests_NSManagedObjectContext: XCTestCase {

    // MARK: - Object Insertion

    func test_NSManagedObjectContext_InsertsManagedObject_WhenObjectConformsToManagedProtocol() {
        let context = MockNSManagedObjectContextCreator.inMemoryContext()
        let changeExpectation = expectation(forNotification: .NSManagedObjectContextObjectsDidChange, object: context, handler: nil)
        let object: MockManaged = context.insertObject()
        object.date = Date()
        wait(for: [changeExpectation], timeout: 2)
    }

    // MARK: - Saving

    func test_NSManagedObjectContext_Saves_WhenChangesHaveBeenMade() {
        let context = MockNSManagedObjectContextCreator.inMemoryContext()
        let saveExpectation = expectation(forNotification: .NSManagedObjectContextDidSave, object: context, handler: nil)
        let object: MockManaged = context.insertObject()
        object.date = Date()
        do {
            try context.saveIfHasChanges()
        } catch {
            XCTFail("Expected successful save")
        }
        wait(for: [saveExpectation], timeout: 2)
    }

    func test_NSManagedObjectContext_DoesNotSave_WhenNoChangesHaveBeenMade() {
        let context = MockNSManagedObjectContextCreator.inMemoryContext()
        let saveExpectation = expectation(forNotification: .NSManagedObjectContextDidSave, object: context, handler: nil)
        saveExpectation.isInverted = true
        do {
            try context.saveIfHasChanges()
        } catch {
            XCTFail("Unexpected error: \(error)")
        }
        wait(for: [saveExpectation], timeout: 2)
    }

}

我在做什么导致测试中出现错误?


自动缓存后

这不应该再发生了NSPersistent[CloudKit]Container(name: String),因为它现在似乎会自动缓存模型(Swift 5.1、Xcode 11、iOS13/MacOS V10.15)。

预自动缓存

NSPersistentContainer/NSPersistentCloudKitContainer确实有两个构造函数:

  • 初始化(名称:字符串) https://developer.apple.com/documentation/coredata/nspersistentcontainer/1640557-init
  • 初始化(名称:字符串, ManagedObjectModel模型:NSManagedObjectModel) https://developer.apple.com/documentation/coredata/nspersistentcontainer/1640584-init

第一个只是一个方便的初始化程序,使用从磁盘加载的模型调用第二个。问题是加载相同的NSManagedObjectModel两次从同一磁盘内app/test invocation导致上述错误,因为每次加载模型都会导致外部注册调用,一旦调用第二次,就会打印错误app/test invocation. And init(name: String) was不够智能,无法缓存模型。

因此,如果您想多次加载容器,则必须加载NSManagedObjectModel一次并将其存储在一个属性中,然后在每个属性中使用init(name:managedObjectModel:) call.

示例:缓存模型

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))
    }
}

旧答案

加载核心数据有点神奇,从磁盘加载模型并使用它意味着它会注册某些类型。第二次加载尝试再次注册该类型,这显然告诉您已经为该类型注册了某些内容。

您只能加载一次核心数据,并在每次测试后清理该实例。清理意味着删除每个对象实体然后保存。有一些函数可以为您提供所有实体,然后您可以获取和删除这些实体。批量删除在内存中不可用,但它是逐个托管对象存在的。

(可能更简单)的替代方案是加载模型一次,将其存储在某个地方,然后在每次调用时重用该模型。NSPersistentContainer调用时,它有一个构造函数来使用给定的模型,而不是从磁盘再次加载它。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

多个 NSEntityDescription 声明 NSManagedObject 子类 的相关文章

  • 获取实体的请求。attribute == @"somevalue"

    如何设置提取请求以仅从具有一个特定值的实体属性中提取数据 这是我之前使用过的基本代码 void fetchResults NSFetchRequest fetchRequest NSFetchRequest fetchRequestWith
  • 如何从 iPhone 中删除 coredata

    您知道当您更改实体结构时如何重置 iPhone 模拟器上的核心数据存储吗 当我创建的核心数据存储的新版本与我上次在 iPhone 上运行的版本不同时 是否需要执行类似的过程 如果可以的话 请问如何 Thanks 只是为了方便起见 除非您编写
  • existingObjectWithID 与 NPrivateQueueConcurrencyType 发生死锁

    我遇到了冻结 死锁 NSPrivateQueueConcurrencyType并发类型而不是NSMainQueueConcurrencyType 我的上下文初始化 managedObjectContext NSManagedObjectCo
  • 核心数据:executeFetchRequest 与 PerformFetch

    我想要一份关于两者之间比较的完整列表 我所知道的事情 executeFetchRequest 消息已发送至 MOC 返回托管对象的数组 目标 从持久存储中获取对象到 MOC With table view 与表视图无关 频率 经常在循环中使
  • NSFetchedResultsController 在 VIPER 架构中的位置是什么?

    In VIPER https www objc io issues 13 architecture viper 与MVC不同的是 NSFetchedResultsController的角色和地点没有那么明确的定义 把它放在交互器上合适吗 根
  • UITableView 未更新

    我正在使用核心数据模型和 UITableViewController 表视图 我的模型似乎工作得很好 但是当我向模型添加实体时 我的表视图没有更新 我相信我的模型有效的原因是 当我添加一个实体时 在运行时视图中不会显示任何内容 但是如果我剪
  • 使用 CoreData 进行 Swift 包单元测试

    我有一堆快速文件 它们提供了 CoreData 之上的一些服务 我的单元测试运行良好 我决定使用 XCode 11 将所有这些移至 Swift 包中 单元测试不再运行 运行时错误为caught NSInternalInconsistency
  • CoreData 多对多添加错误

    不确定我在这里做错了什么 School has a to many to Student and Student has its inverse 一点测试代码如下 class Student interface School NSManag
  • 如何让NSManagedObject不出错?

    我目前正在调试另一个开发人员编写的一个大项目 该项目使用CoreData我对此很陌生 我遇到了崩溃 这是由于某些NSManagedObject是一个错误 我对什么是错误不太了解 我想将对象转换为 非错误 看看它是否有帮助 阅读文档让我想到t
  • 如何在核心数据中保存通用测量<单位>?

    如何在核心数据中保存和检索通用测量 我想做的是保存Measurement
  • Swift 2.0 中的 countForFetchRequest

    我正在尝试使用countForFetchRequestSwift 2 0 中托管对象上下文上的方法 我注意到错误处理executeFetchRequest已更改为新的do try catch syntax func executeFetch
  • 使用“对多”关系从 NSFetchedResultsController 派生 UITableView 部分

    我的核心数据模型如下所示 article lt gt gt category 是否可以远程使用NSFetchedResultsController生成一个看起来像这样的 UITableView Category 1 Article A Ar
  • 将实体添加到核心数据

    我们有一个使用核心数据的应用程序 在下一个版本中 我想向现有实体添加一个新实体 只需添加新的然后从软件中填充它就可以了吗 还是有什么我必须考虑的事情 迁移有几种类型 最简单的是使用推断映射模型的轻量级迁移 这意味着您只需告诉它进行迁移 软件
  • 具有多个 sqlite 文件的核心数据

    如何将 Core Data 与多个 SQLite 文件一起使用 每个文件都包含相同的结构 但数据是从不同的位置检索的 我希望能够在运行时根据应用程序设置在这些 sqlite 文件之间切换 当然 只需指向持久存储协调器 NSPersisten
  • 使用按计数分组的核心数据获取属性

    这是我想为 Core Data 编写的查询的 SQL 版本 SELECT Group Name COUNT Item Name FROM Item INNER JOIN Group ON Item GroupID Group ID GROU
  • 如何从 Xcode 4 中的实体创建用户界面?

    我已经用核心数据进行了几天的实验 并且在过去的几个小时里尝试找出如何从 xcode 4 中的实体创建 UI 根据我一直在阅读的书籍 您必须选择将核心数据实体拖到界面生成器中的窗口中 但是当我在 xcode 4 中执行此操作时 没有任何反应
  • 在视图之间传递核心数据实体变量

    我无法理解如何在视图之间使用核心数据实体变量 为了更好地理解我的问题是什么 我的代码如下 View A 基本上 您必须将完整预算实体或相关预算实体的 ID 从视图 A 传递到视图 B 由于不知道您的应用程序的视图层次结构和逻辑 我假设您选择
  • 如何解决 CoreData mogenerator 未找到问题

    我收到如下所示的错误 我不知道我错过了什么 我该如何解决这个问题 如下图所示 Users nischalhada Documents XcodePro mnepalnews revisited 2 0 CoreData mogenerato
  • 错误:更改核心数据模型后架构armv7的重复符号

    我有一个使用核心数据框架的应用程序 我工作得很好 我刚刚更改了数据模型 向一个实体添加一个属性 当我尝试构建它时 出现错误 duplicate symbol OBJC METACLASS AccountFolder in Users XXX
  • 填充 CoreData 创建的 sqlite 数据库

    我有一个由 CoreData 模型自动创建的 sqlite DB 但我的应用程序不会让用户能够将数据写入其中 而是我想用程序所需的所有数据预先填充它 我的问题是 CoreData 创建的 sqlite DB 具有未知的表和字段 这些表和字段

随机推荐