使用约束类型参数实现Swift协议

时间:2015-01-28 02:53:05

标签: swift generics

我有几个Swift协议描述了我尝试以多种方式实现的通用接口:

protocol Identifiable
{
    var identifier:String { get }
}

protocol ItemWithReference
{
    var resolveReference<T:Identifiable>(callback:(T) -> ())
}

现在我想使用CloudKit作为后端来实现ItemWithReference协议(这最终将与备用后端一起使用,此时我希望提供{{1的替代实现协议。

在我的CloudKit实现中,我有类似的东西:

ItemWithReference

我想要做的是将class CloudKitIdentifiable : Identifiable { ... } class CloudKitItemWithReference : ItemWithReference { func resolveReference<T:Identifiable>(callback:(T) -> ()) { // In this implementation, I want to only proceed if `T` is a CloudKitIdentifiable subtype // But not sure how to enforce that } } 限制为T,而不仅仅是简单的CloudKitIdentifiable。我无法在Identifiable声明中直接执行此操作,因为该函数不符合resolveReference协议。所以相反,我希望确认T确实是ItemWithReference,然后调用它的初始化程序来创建正在解析的类的新实例。

Swift中有没有办法使用T&#39的元类型CloudKitIdentifiable并确定它是否是另一种类型的子类型?此外,有没有办法调用已在该子类型上声明的必需初始值设定项?

1 个答案:

答案 0 :(得分:2)

尝试:

class CloudKitIdentifiable : Identifiable {
    var identifier:String = ...

    required init() {}
    // you need `required`.
}

class CloudKitItemWithReference : ItemWithReference {

    func resolveReference<T:Identifiable>(callback:(T) -> ()) {
        if T.self is CloudKitIdentifiable.Type {
            // do work..
            let obj = (T.self as CloudKitIdentifiable.Type)()
            callback(obj as T)
        }
    }
}

OR:

class CloudKitItemWithReference : ItemWithReference {
    func resolveReference<T:Identifiable>(callback:(T) -> ()) {
        if let CKT = T.self as? CloudKitIdentifiable.Type {
            // do work..
            let obj = CKT()
            callback(obj as T)
        }
    }
}

但是,在这种情况下,你必须像这样调用resolveReference

let ref = CloudKitItemWithReference()
ref.resolveReference { (obj: CloudKitIdentifiable) -> () in
    //                       ^^^^^^^^^^^^^^^^^^^^ explicit type is necessary.
    println(obj.identifier)
    return
}

Rathar,我建议使用Associated Type

protocol Identifiable {
    var identifier:String { get }
}

protocol ItemWithReference {

    typealias Item: Identifiable // <-- HERE is associated type

    func resolveReference(callback:(Item) -> ())
}

class CloudKitIdentifiable : Identifiable {
    var identifier:String
    init(identifier: String) {
        self.identifier = identifier
    }
}

class CloudKitItemWithReference : ItemWithReference {

    // `Item` associated type can be inferred from
    // the parameter type of `resolveReference()`
    //
    // typealias Item = CloudKitIdentifiable

    func resolveReference(callback:(CloudKitIdentifiable) -> ()) {
        let obj = CloudKitIdentifiable(identifier: "test")
        callback(obj)
    }
}

let ref = CloudKitItemWithReference()
ref.resolveReference { obj in
    println(obj.identifier)
    return
}