类函数返回 Self? 用于核心数据抽象类



我有一个核心数据类List继承自抽象类型Synchronizable。后者是我打算与服务器同步的其他几个类的父级。

我想在Synchronizable中分解一个类函数,该函数返回服务器上具有特定ID的对象:

class func withIDOnServer(_ pk:String, inMOC context:NSManagedObjectContext -> Self? 

并将其用作

List.withIDOnServer(pk:"1234", context)

我遇到的问题是我无法将结果转换为子类类型。这是我的代码:

extension Synchronizable {
// return the object with ID xxx on server. 
class func withIDOnServer(_ pk:String, inMOC context:NSManagedObjectContext) throws -> Self? {
let entityName = String(describing: self)
let request = NSFetchRequest<NSFetchRequestResult>(entityName: entityName)
request.predicate = NSPredicate(format:"'pk' = %@", pk)
do {
let results = try context.fetch(request) as! [Self]
guard results.count == 1 else {
if results.count > 1 {
throw fetchError.moreThanOne(pk: pk)
}
else { // results.count == 0
return nil
}
}
return results.first as! Self?
}
catch let error {
throw fetchError.cannotFetch(error.localizedDescription)
}
}

}

问题是在函数体中使用Self。(我也试过Self?type(of:self),没有运气( 如何返回与子类类型相同的对象?使用协议的唯一方法(函数体中允许Self(吗?

这将需要 Swift 泛型才能工作。使用 Swift 泛型类型代替Self。类似的东西

extension Synchronizable {
// return the object with ID xxx on server. 
class func withIDOnServer<T:Synchronizable>(_ pk:String, inMOC context:NSManagedObjectContext) throws -> T? {
let entityName = String(describing: self)
let request = NSFetchRequest<NSFetchRequestResult>(entityName: entityName)
request.predicate = NSPredicate(format:"'pk' = %@", pk)
do {
let results = try context.fetch(request) as! [T]
guard results.count == 1 else {
if results.count > 1 {
throw fetchError.moreThanOne(pk: pk)
}
else { // results.count == 0
return nil
}
}
return results.first as! T?
}
catch let error {
throw fetchError.cannotFetch(error.localizedDescription)
}
}

若要让编译器推断出正确的类型,需要在调用函数时通过声明所需的类型来明确说明。类似的东西

let myList: List? = Synchronizable.withIDOnServer("asdf", inMOC: context)

如果您考虑一下,在基类上声明一个返回类型为Self的函数没有任何意义。除非子类覆盖该函数,否则在子类上调用它将调用基类的实现,并且它不能根据self的类神奇地更改其返回类型。

假设核心数据提取请求返回一个List,该是此函数应返回的对象类型。您能确定查询的结果都是List的实例吗?如果没有,将结果转换为List至少是不安全的。

让这个函数返回ListSynchronizable后,您可以考虑向每个子类添加一个函数,该函数将强制转换为子类,例如,如果Foo是一个子类,它可能会像(未测试(

class Foo: Synchronizable 
{
class functions getInstance(_ pk:String, inMOC context:NSManagedObjectContext) throws -> Foo? 
{
guard let ret = try withIDOnServer(pk, context: context) as? Foo
else { throw MyError.classCast }
}
return ret
}

最新更新