【问题标题】:How do I avoid a crash if entity name is wrong in Core Data count/fetch request?如果核心数据计数/获取请求中的实体名称错误,如何避免崩溃?
【发布时间】:2018-09-07 17:38:49
【问题描述】:

我正在为我的所有持久性存储类编写一个通用基类。每个子类都将使用 Core Data 处理持久数据库中的一个特定实体/表。线程似乎工作正常,我可以正确计算表中的项目数。问题是,如果获取请求中的实体名称错误,我不会得到异常,我会崩溃。由于这是一个字符串,并且是程序员在代码中的某个位置键入的,因此我想以更好的方式检测错误,以便提醒程序员使用了无效的实体名称。

这是我的代码:

class Store<EntityType:NSFetchRequestResult> : NSObject {
    private var entityName : String = ""
    init( entityName : String ) {
        self.entityName = entityName
    }

    public var Count : Int
    {
        get {
            var fetchResults : Int = 0
            objc_sync_enter( self )
            do {

                var privateContext : NSManagedObjectContext? = nil
                DispatchQueue.main.sync {
                    let deleg = UIApplication.shared.delegate as! AppDelegate
                    privateContext = deleg.privateManagedObjectContext
                }

                if privateContext == nil
                    { return 0 }

                privateContext!.performAndWait {
                    do
                    {
                        let request = NSFetchRequest<EntityType>( entityName: self.entityName )
                        fetchResults = try privateContext!.count( for: request )
                    } catch
                    {
                        print("Unexpected error: \(error).")
                    }
                }
            }
            objc_sync_exit( self )
            return fetchResults
        }
    }
...

使用错误的实体名称,MOC 上的 count() 函数会导致 SIGABRT 并且不会引发任何异常。

如何以某种方式捕获错误?

我也向 cmets 开放关于线程和在后台线程中使用它的问题。它现在可以工作,但由于互联网和 Apple 都对如何在后台线程中使用 Core Data 提出了模糊的说法,因此非常感谢您的帮助。

我刚才也试过这个:

let request = NSFetchRequest<EntityType>( entityName: String(reflecting: EntityType.self) )

名称采用“app name.entityname”的形式,因此它可能是可用的。但是由于编辑器允许程序员为实体和类输入不同的名称,这根本不安全。如果我可以在运行时以某种方式检查名称是否有效,我将使用此方法。但是如果不解决崩溃问题,我现在不愿意更改任何内容。

【问题讨论】:

  • Xcode 将实体名称作为字符串存储在它从编辑器中的实体信息生成的类扩展中的函数调用中。但是由于不可能提前创建没有名称的实体类的实例,所以我无法以某种方式从该函数中获取名称。我必须把它交给 Apple,他们刚刚添加了一个函数来在创建实体类扩展时返回字符串名称,从而使所有这些文字字符串废话都消失了。但我猜他们的程序员喜欢在他们的代码中输入字符串文字。呃。

标签: ios swift multithreading core-data nsmanagedobjectcontext


【解决方案1】:

可以获得上下文模型中存在的实体名称列表。

这样,您可以在执行获取请求之前检查程序员提供的实体名称是否有效。

//get the context and make sure it's not nil
guard let privateContext = privateContext 
else { 
    print("Unexpected error: context is nil.")
    return 0 
}

//get the names of entities in the model associated with this context
// credit: Snowman, https://stackoverflow.com/questions/5997586/core-data-list-entity-names
guard let names = privateContext.persistentStoreCoordinator?.managedObjectModel.entities.map({ (entity) -> String? in
    return entity.name
}) 
else { 
    print("Unexpected error: Could not get entity names from model.")
    return 0 
}

//make sure the name specified by the programmer exists in the model    
guard names.contains(where: { (name) -> Bool in
    return name == self.entityName
})
else {
    print("Unexpected error: \(self.entityName) does not exist in the model.")
    return 0 
}

privateContext.performAndWait {
    do 
    {
        let request = NSFetchRequest<EntityType>( entityName: self.entityName )
        fetchResults = try privateContext.count( for: request )
    } catch
    {
        print("Unexpected error: \(error).")
    }
}

如果您想了解性能:在我的测试中,为具有 20 个实体的模型检索实体名称列表 500 次需要 20 毫秒。没什么好担心的。

【讨论】:

    猜你喜欢
    • 2019-05-21
    • 1970-01-01
    • 1970-01-01
    • 2010-12-28
    • 2019-11-06
    • 2011-09-13
    • 2019-08-07
    • 1970-01-01
    相关资源
    最近更新 更多