尝试创建使用协议和泛型的函数时出错

时间:2014-10-29 09:54:07

标签: ios xcode generics swift

我有一个打算返回符合PanelControllerProtocol的类的类。我遇到的问题是获取anyClass对象并将其转换为T.

func classFromBundle<T: PanelControllerProtocol>(className: String) -> T {
    let bundleClassString = classBundleAndName(className)
    var anyClass : AnyClass = NSClassFromString(bundleClassString)
}

如果我试试这个:

var panelControllerType = anyClass as T

我明白了:

  

“无法从具体类型'AnyClass'转换为类型变量'T'   它与约束条件不匹配“。

尝试简单地返回anyClass会给我一个错误:

  

'AnyClass'不能转换为'T'

尝试将我的方法名称更改为:

func classFromBundle<T where T: AnyClass, T: PanelControllerProtocol>(className: String) -> T

给出错误:

  

类型'T'约束为非协议类型'AnyClass'

此外,一旦我弄清楚如何返回正确的对象,我不知道如何调用该类。目前,调用上述方法如下:

classFromBundle("Test")

给出错误:

  

无法将表达式的类型'NSString'转换为'String'类型

1 个答案:

答案 0 :(得分:0)

您可以使用以下代码:

var instance: AnyObject? = NSClassFromString(bundleClassString)
let actualClassInstance = instance as T

return actualClassInstance

但是,正如您可能猜到的,如果找不到类类型,则会生成运行时异常。

更好的解决方案是让您的函数返回一个可选的T,并为NSClassFromString帐户创建T类的实例失败:

var actualClassInstance: T?

var instance: AnyObject? = NSClassFromString(bundleClassString)

if instance != nil {
    actualClassInstance = instance as? T
}

return actualClassInstance

请注意NSClassFromString,相应于文档:

  

返回:由aClassName命名的类对象,如果当前没有加载该名称的类,则返回nil。

返回错误的类型AnyObject!,而应该是AnyObject?

要调用该函数,您只需要告诉编译器T是什么 - 并且您可以通过从函数结果分配给的变量中推断类型来实现:

let concreteClass: ConcreteClass = classFromBundle("ConcreteClass")
                   ^^^^^^^^^^^^^
                   This tells the compiler what T is

如果您使用的是代码的第二个(更安全)版本,那么您应该将变量声明为可选:

let concreteClass: ConcreteClass? = classFromBundle("ConcreteClass")