Swift 4:Generics的问题

时间:2018-01-31 16:12:48

标签: swift swift4 xcode9

作为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,它实现SomeModelObjectCodable或将来可能还有别的东西,所以通常的类型替换在编译时,无论如何都要工作。

有什么建议吗?在Swift中完全不可能做到吗?

2 个答案:

答案 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协议。你不能上课和协议类型一起。

因此,错误就像它说的那样。

非协议,非类型类型'ResponseMappedClass'不能在协议约束类型中使用

这样的东西将起作用,因为两种类型都是协议。

as! (DataResponse<Codable & Decodable>) -> Void