您正在以错误的方式接近它:在Swift中,与Objective-C不同,类具有特定类型,甚至具有继承层次结构(即,如果类 B 继承自 A ,则 B.Type 也继承自 A.Type ):
class A {}
class B: A {}
class C {}
// B inherits from A
let object: A = B()
// B.Type also inherits from A.Type
let type: A.Type = B.self
// Error: 'C' is not a subtype of 'A'
let type2: A.Type = C.self
's why you shouldn' t使用 AnyClass ,除非你真的想允许任何类 . 在这种情况下,正确的类型将是 T.Type ,因为它表示 returningClass 参数和闭包参数之间的链接 .
实际上,使用它而不是 AnyClass 允许编译器正确地推断方法调用中的类型:
class func invokeService(service: String, withParams params: Dictionary, returningClass: T.Type, completionHandler handler: ((T) -> ())) {
// The compiler correctly infers that T is the class of the instances of returningClass
handler(returningClass())
}
现在有一个构建 T 实例传递给 handler 的问题:如果你现在尝试运行代码,编译器会抱怨 T 不能用 () 构造 . 理所当然地: T 必须明确约束,要求它实现特定的初始化程序 .
这可以通过以下协议来完成:
protocol Initable {
init()
}
class CityInfo : NSObject, Initable {
var cityName: String?
var regionCode: String?
var regionName: String?
// Nothing to change here, CityInfo already implements init()
}
然后,您只需将 invokeService 的通用约束从 更改为 .
提示
如果您遇到奇怪的错误,例如“无法将表达式的类型'()'转换为'String'”类型,则将方法调用的每个参数移动到其自己的变量通常很有用 . 它有助于缩小导致错误的代码并发现类型推断问题:
let service = "test"
let params = ["test" : "test"]
let returningClass = CityInfo.self
CastDAO.invokeService(service, withParams: params, returningClass: returningClass) { cityInfo in /*...*/
}
现在有两种可能性:错误移动到其中一个变量(这意味着错误的部分存在)或者你得到一个神秘的消息,如“无法将表达式的类型 () 转换为类型 ($T6) -> ($T6) -> $T5 ” .
后一个错误的原因是编译器无法推断您编写的类型 . 在这种情况下,问题是 T 仅用于闭包的参数,并且您传递的闭包不知道要推断的类型 . 通过将 returningClass 的类型更改为包含 T ,您可以为编译器提供确定泛型参数的方法 .