前端之家收集整理的这篇文章主要介绍了
swift – 如何将类类型作为函数参数传递,
前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我有一个通用的
函数,
调用一个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作为参数类型正确的事情吗?
此外,当调用方法时,我传递MyObject.self作为returningClass值,但我得到一个编译错误“无法转换表达式的类型'()’类型’字符串’
CastDAO.invokeService("test",withParams: ["test" : "test"],returningClass: CityInfo.self) { cityInfo in /*...*/
}
任何帮助将不胜感激。
谢谢
编辑:我尝试使用object_getClass,由holex提及,现在我得到这个错误:“类型’CityInfo.Type’不符合协议’AnyObject’”。需要做什么以符合协议?
class CityInfo : NSObject {
var cityName: String?
var regionCode: String?
var regionName: String?
}
@H_
403_22@
你在
错误的方式接近它:在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
这就是为什么你不应该使用AnyClass,除非你真的想允许任何类。在这种情况下,正确的类型将是T.Type,因为它表达了returningClass参数和闭包的参数之间的链接。
事实上,使用它而不是AnyClass允许编译器正确地推断方法调用中的类型:
class func invokeService<T>(service: String,returningClass: T.Type,completionHandler handler: ((T) -> ())) {
// The compiler correctly infers that T is the class of the instances of returningClass
handler(returningClass())
}
现在有一个问题,构造一个T的实例传递给处理程序:如果你现在尝试并运行代码,编译器会抱怨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> ;. 小费 如果你得到奇怪的错误,如“无法将表达式的类型()’转换为类型”字符串“,通常有用的是将方法调用的每个参数移动到自己的变量。它有助于缩小导致错误的代码并揭示类型推断问题:
let service = "test"
let params = ["test" : "test"]
let returningClass = CityInfo.self
CastDAO.invokeService(service,withParams: params,returningClass: returningClass) { cityInfo in /*...*/
}
现在有两种可能性:错误移动到其中一个变量(这意味着错误的部分存在)或者你得到一个隐藏的消息,如“无法将表达式的type()转换为类型($ T6) – >($ T6)→> $ T5“。
后一个错误的原因是编译器不能推断你写的类型。在这种情况下,问题是T只用在闭包的参数中,而你传递的闭包不指示任何特定类型,所以编译器不知道要推断什么类型。通过更改returningClass的类型以包括T,您可以为编译器提供一种确定通用参数的方法。