如何传递一个类的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是城市信息对象。