如果 Core Data count/fetch 请求中的实体名称错误,如何避免崩溃?
How do I avoid a crash if entity name is wrong in Core Data count/fetch request?
我正在为我的所有持久性存储 class 编写通用基础 class。每个 child class 将在使用核心数据的持久数据库中与一个特定的 entity/table 一起工作。线程似乎工作正常,我可以正确获取 table 中的项目数。问题是如果获取请求中的实体名称是错误的,我不会得到异常,我会崩溃。由于这是一个字符串并且由程序员在代码中的某处键入,我想以某种更好的方式检测错误,以便提醒程序员使用了无效的实体名称。
这是我的代码:
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 并且不会抛出任何异常。
如何以某种方式捕获错误?
我也愿意接受有关线程和在后台线程中使用它的评论。它现在可以工作,但是由于互联网和 Apple 都对如何在后台线程中使用 Core Data 含糊其词,因此不胜感激。
我刚才也试过了:
let request = NSFetchRequest<EntityType>( entityName: String(reflecting: EntityType.self) )
名字的格式是"app name.entityname",所以可能有用。但是由于编辑器允许程序员为实体和 class 输入不同的名称,这一点也不安全。如果我能以某种方式在运行时检查名称是否有效,我将使用此方法。但是不解决崩溃问题,我现在不愿意改变任何东西。
可以获取上下文模型中存在的实体名称列表。
这样,您可以在执行获取请求之前检查程序员提供的实体名称是否有效。
//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,
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 毫秒。不用担心。
我正在为我的所有持久性存储 class 编写通用基础 class。每个 child class 将在使用核心数据的持久数据库中与一个特定的 entity/table 一起工作。线程似乎工作正常,我可以正确获取 table 中的项目数。问题是如果获取请求中的实体名称是错误的,我不会得到异常,我会崩溃。由于这是一个字符串并且由程序员在代码中的某处键入,我想以某种更好的方式检测错误,以便提醒程序员使用了无效的实体名称。
这是我的代码:
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 并且不会抛出任何异常。
如何以某种方式捕获错误?
我也愿意接受有关线程和在后台线程中使用它的评论。它现在可以工作,但是由于互联网和 Apple 都对如何在后台线程中使用 Core Data 含糊其词,因此不胜感激。
我刚才也试过了:
let request = NSFetchRequest<EntityType>( entityName: String(reflecting: EntityType.self) )
名字的格式是"app name.entityname",所以可能有用。但是由于编辑器允许程序员为实体和 class 输入不同的名称,这一点也不安全。如果我能以某种方式在运行时检查名称是否有效,我将使用此方法。但是不解决崩溃问题,我现在不愿意改变任何东西。
可以获取上下文模型中存在的实体名称列表。
这样,您可以在执行获取请求之前检查程序员提供的实体名称是否有效。
//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,
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 毫秒。不用担心。