【问题标题】:Class function returning Self? for Core Data abstract class类函数返回 Self?核心数据抽象类
【发布时间】:2018-10-09 11:09:17
【问题描述】:

我有一个核心数据类 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 inheritance core-data return-type introspection


【解决方案1】:

如果您考虑一下,在您的基类上声明一个返回类型为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
}

【讨论】:

    【解决方案2】:

    这需要 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)
    

    【讨论】:

    • 完美,谢谢!我什至可以直接List.withIDOnServer(....)。这是正确的答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-12-01
    • 1970-01-01
    • 2016-09-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多