如何传递一个类的types作为函数参数

我有一个通用的函数调用一个Web服务,并将JSON响应序列化回一个对象。

class func invokeService<T>(service: String, withParams params: Dictionary<String, String>, returningClass: AnyClass, completionHandler handler: ((T) -> ())) { /* Construct the URL, call the service and parse the response */ } 

我试图完成的是这个Java代码的等价物

 public <T> T invokeService(final String serviceURLSuffix, final Map<String, String> params, final Class<T> classTypeToReturn) { } 

首先,我想要完成的是我的方法签名? 更具体地说,指定AnyClass作为参数types是正确的事情吗?

此外,当调用方法,我传递MyObject.self作为returningClass值,但我得到一个编译错误“无法转换expression式的types'()'键入'string'”

 CastDAO.invokeService("test", withParams: ["test" : "test"], returningClass: CityInfo.self) { cityInfo in /*...*/ } 

任何帮助,将不胜感激。

谢谢

编辑:我尝试使用object_getClass,由holex提到,现在我得到这个错误:“types'CityInfo.Type'不符合协议'AnyObject'”。 需要做什么才能符合协议?

 class CityInfo : NSObject { var cityName: String? var regionCode: String? var regionName: String? } 

你正在以一种错误的方式接近它:在Swift中,与Objective-C不同,类有特定的types,甚至有一个inheritance层次结构(即如果B类inheritance自A ,那么B.Type也inheritance自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 

这就是为什么你不应该使用AnyClass ,除非你真的想要任何类。 在这种情况下,正确的types是T.Type ,因为它表示了T.Type参数和闭包参数之间的关系。

事实上,使用它而不是AnyClass允许编译器正确地推断方法调用中的types:

 class func invokeService<T>(service: String, withParams params: Dictionary<String, String>, 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的通用约束从<T>更改为<T: Initable>

小费

如果你得到奇怪的错误,如“不能转换expression式的types'()'键入'string'”,通常将方法调用的每个参数移动到它自己的variables是有用的。 它有助于缩小导致错误的代码并发现types推断问题:

 let service = "test" let params = ["test" : "test"] let returningClass = CityInfo.self CastDAO.invokeService(service, withParams: params, returningClass: returningClass) { cityInfo in /*...*/ } 

现在有两种可能性:错误移动到其中一个variables(这意味着错误的部分在那里),或者你得到一个神秘的信息,如“不能转换expression式的types()到types($T6) -> ($T6) -> $T5 “。

后一个错误的原因是编译器不能推断你写的东西的types。 在这种情况下,问题在于T只用在闭包的参数中,而你传递的闭包并不表示任何特定的types,所以编译器不知道要推断什么types。 通过改变returnsClasstypes来包含T你可以给编译器一个确定generics参数的方法。

你可以通过这种方式获得AnyObject的类:

Swift 3.x

 let myClass: AnyClass = type(of: self) 

Swift 2.x

 let myClass: AnyClass = object_getClass(self) 

如果你愿意的话,你可以把它作为parameter passing。

使用obj-getclass

 CastDAO.invokeService("test", withParams: ["test" : "test"], returningClass: obj-getclass(self)) { cityInfo in /*...*/ } 

假设self是城市信息对象。