有关如何使用泛型类,实现协议的任何想法,都应该转换为该协议并允许检索属性?

时间:2015-02-03 10:05:59

标签: swift generics

我有一个简单的Result对象,它应该包含一个对象(类,结构或枚举)和一个Bool来说明它是否被取消。我需要沿着它的路径询问这个对象(在它到达目的地之前,目的地知道期望什么样的对象)来确定它是否被取消(当时没有担心伴随的对象)。我的对象看起来像:

import Foundation

@objc protocol Resultable {
    var didCancel: Bool { get }
}

class Result<T>: Resultable {
    let didCancel: Bool
    let object: T?

    init(didCancel: Bool, object: T?) {
        self.didCancel = didCancel
        self.object = object
    }
}

我的Result对象可以包装didCancel标志和实际对象(可以是任何类型),以及它实现Resultable协议的意思我可以在任何时候询问它,看看是否通过将其转换为Resultable来取消它。

我理解(虽然不喜欢它)协议必须以@objc为前缀,以便我们可以投射到它(根据Apple文档)。不幸的是,当我运行下面的代码(在游乐场或项目中)时,我收到一条令人讨厌的"does not implement methodSignatureForSelector:"错误消息:

let test = Result(didCancel: false, object: NSArray())

println(test.didCancel)
// transform the object into the form it will be received in
let anyTest: AnyObject = test

if let castTest = anyTest as? Resultable {
    println(castTest.didCancel)
}

似乎尽管协议以@objc为前缀,但它也希望实际的类继承自NSObject(这不是Apple明确要求的要求)。对于泛型类来说,这显然是一个问题。

这里有什么我想念的吗?有什么办法让这个工作?如果做不到的话,是否有任何变通方法(尽管我坚信这种事情应该是可能的 - 也许我们可以希望Apple在某个阶段会废除@objc协议转换要求)?

更新 看起来这是用Swift 1.2解决的 您现在可以转换为非ObjC协议,并且该对象不必从NSObject继承。

1 个答案:

答案 0 :(得分:3)

  

似乎尽管协议以@objc为前缀,但它也希望实际的类继承自NSObject

事实并非如此。例如,以下代码按预期工作:

@objc protocol MyProtocol {
    var flag: Bool { get }
}

class MyClass: MyProtocol {
    let flag = true
}

let foo:AnyObject = MyClass()
if let p = foo as? MyProtocol {
    println(p.flag)
}

问题是:在Swift Generic类中声明的任何方法/属性在Objective-C中是不可见的。因此,从@objc protocol Resultable的角度来看,didCancel中声明的Result<T>属性是不可见的。这就是调用methodSignatureForSelector:的原因。

此处的解决方法非常烦人:您必须拥有实现Result的{​​{1}}的非通用基类。

didCancel