作为Objective-C开发人员多年后,我是Swift的新手。我很难理解类型转换如何与泛型一起使用。
我有两个使用Alamofire + Codable和Alamofire + ObjectMapper进行对象映射的函数。像这样:
onConfirmActionPressed
public func performRestOperationWithDecodable<ResponseClass: Decodable>(
_ restOperationType: NetworkServiceRestOperationType,
pathUrl: URLConvertible,
parameters: Parameters,
encoding: ParameterEncoding,
savedAuthType: NetworkServiceAuthType,
activityIndicator: ActivityIndicatorProtocol?,
successBlock: @escaping (_ responseObject: DataResponse<ResponseClass>) -> Void,
errorBlock:@escaping (_ error: Error, _ validResponse: Bool) -> Void) {
let restConfiguration = self.setupRestOperation(
savedAuthType: savedAuthType,
pathUrl: pathUrl,
activityIndicator: activityIndicator)
Alamofire
.request(
restConfiguration.url,
method: .get,
parameters: parameters,
encoding: encoding,
headers: restConfiguration.headers)
.validate(
contentType: Constants.Network.DefaultValidContentTypeArray)
.responseDecodableObject(
queue: self.dispatchQueue,
keyPath: nil,
decoder: JSONDecoder(),
completionHandler: { (responseObject: DataResponse<ResponseClass>) in
self.completionRestOperation(
responseObject: responseObject,
activityIndicator: activityIndicator,
successBlock: successBlock,
errorBlock: errorBlock)
})
}
每个函数都有一个泛型类型,它符合所使用的映射器所需的适当协议(可解码为Codable,可映射为ObjectMapper)。这些功能可以按照预期进行压缩和工作。 现在我尝试编写第三个具有第三个泛型类型的函数,但不符合任何协议,并根据配置参数强制转换为适当的泛型。这样的事情:
public func performRestOperationWithObjectMapper<ResponseClass: BaseMappable>(
_ restOperationType: NetworkServiceRestOperationType,
pathUrl: URLConvertible,
parameters: Parameters,
encoding: ParameterEncoding,
savedAuthType: NetworkServiceAuthType,
activityIndicator: ActivityIndicatorProtocol?,
successBlock: @escaping (_ responseObject: DataResponse<ResponseClass>) -> Void,
errorBlock: @escaping (_ error: Error, _ validResponse: Bool) -> Void) {
let restConfiguration = self.setupRestOperation(
savedAuthType: savedAuthType,
pathUrl: pathUrl,
activityIndicator: activityIndicator)
Alamofire
.request(
restConfiguration.url,
method: .get,
parameters: parameters,
encoding: encoding,
headers: restConfiguration.headers)
.validate(
contentType: Constants.Network.DefaultValidContentTypeArray)
.responseObject(
queue: self.dispatchQueue,
keyPath: nil,
mapToObject: nil,
context: nil,
completionHandler: { (responseObject: DataResponse<ResponseClass>) in
self.completionRestOperation(
responseObject: responseObject,
activityIndicator: activityIndicator,
successBlock: successBlock,
errorBlock: errorBlock)
})
}
根据说明:public func performRestOperation<ResponseMappedClass :AnyObject>(
_ restOperationType: NetworkServiceRestOperationType,
pathUrl: URLConvertible,
parameters: Parameters = [:],
encoding: ParameterEncoding = URLEncoding.queryString,
savedAuthType: NetworkServiceAuthType,
activityIndicator: ActivityIndicatorProtocol?,
successBlock: @escaping (_ responseObject: ResponseMappedClass) -> Void,
errorBlock: @escaping (_ error: Error, _ validResponse: Bool) -> Void) {
if self.canDoRestOperation(errorBlock: errorBlock) != true {
return
}
switch self.mappingType {
case .Codable:
self.performRestOperationWithDecodable(
restOperationType,
pathUrl: pathUrl,
parameters: parameters,
encoding: encoding,
savedAuthType: savedAuthType,
activityIndicator: activityIndicator,
successBlock: { (responseObject: DataResponse<ResponseMappedClass>) in
let response: ResponseMappedClass = responseObject.result.value!
successBlock(response)
} as! (DataResponse<ResponseMappedClass & Decodable>) -> Void,
errorBlock: { (error: Error, validResponse: Bool) in
errorBlock(error, validResponse)
})
case .ObjectMapper:
// TODO
break
}
}
,我试图从&#34;泛型&#34;类类型as! (DataResponse<ResponseMappedClass & Decodable>) -> Void
到同一个类,但支持ResponseMappedClass
。
但该指令无法编译:
非协议,非类型&#39; ResponseMappedClass&#39;不能使用 在协议约束类型中
在完成所有这些过程之后,各种泛型将代表同一个类,例如Codable
,它实现SomeModelObject
,Codable
或将来可能还有别的东西,所以通常的类型替换在编译时,无论如何都要工作。
有什么建议吗?在Swift中完全不可能做到吗?
答案 0 :(得分:0)
我认为将泛型类型与协议结合使用是不可能的。编译器不将它们视为类或协议类型。您的代码还有一件事是错误的,您使用self.mappingType
来确定它是Decodable
还是Mapable
类型。如果self.mappingType == .Codable
,但ResponseMappedClass
未向Decodable
协议确认,该怎么办?我可以向你建议的是函数重载。创建3个功能:
public func performRestOperation<ResponseMappedClass: AnyObject>(...) where ResponseMappedClass: Decodable {
}
public func performRestOperation<ResponseMappedClass: AnyObject>(...) where ResponseMappedClass: BaseMappable {
}
public func performRestOperation<ResponseMappedClass: AnyObject>(...) {
}
在最后一个只是抛出一个错误。将根据通用参数类型调用右侧函数。
答案 1 :(得分:0)
(DataResponse<ResponseMappedClass & Decodable>)
我认为您错误的是ResponseMappedClass
是类而另一方面Decodable
是协议。你不能上课和协议类型一起。
因此,错误就像它说的那样。
这样的东西将起作用,因为两种类型都是协议。
as! (DataResponse<Codable & Decodable>) -> Void