AlexBerd
AlexBerd

Reputation: 1504

Swift 4: Downcast callback function issue

I have an API class for server side connection:

class APIClient {

    typealias CompletionHandler = (CodabilityResponse) -> Void

    @discardableResult
    private static func performRequest<T:Decodable>(route: APIRouter, completion: @escaping (T) -> Void) -> DataRequest {
        return Alamofire.request(route).responseJSON(completionHandler: { (response) in
            do {
                //print("The response is: \(response.result.value)")
                let json = try JSONDecoder().decode(T.self, from: response.data!)
                completion(json)
            } catch let err {
                print("Err", err)
            }
        })
    }


    static func login(loginData: LoginRequest, completion: @escaping (LoginResponse) -> Void) {
        performRequest(route: APIRouter.login(loginData: loginData)) { (response) in
            self.commonCompletion(response: response, for: completion)
        }
    }

Each response in my application inherit from CodablityResponse protocol, which inherit from Codabilty protocol:

protocol Codability: Codable { }

    extension Codability {
        typealias T = Self
        func encode() -> Data? {
            return try? JSONEncoder().encode(self)
        }

        static func decode(data: Data) -> T? {
            return try? JSONDecoder().decode(T.self, from: data)
        }
    }

    protocol CodabilityResponse: Codability {

        var status: String { get }
        var errorMessage: [String]? { get }
        var errorCode: Int { get }
    }

    extension CodabilityResponse { }

My common completion function is looks like:

private static func commonCompletion(response: CodabilityResponse, for commonCompletion: @escaping CompletionHandler) {
        if response.status == APIStatus.success.rawValue && response.errorCode == APIErrors.OK.rawValue {
            commonCompletion(response)
        }
        else {
            //TODO SHOW ERROR ONLY IN THIS PLACE

        }
    }

The problem is in this row self.commonCompletion(response: response, for: completion), it can not downcast from (LoginResponse)->Void to (CodabilityResponse)-> Void in spite the fact that LoginResponse inherits from CodabilityResponse If I add force casting then I get next error: Generic parameter 'T' could not be inferred

I broke my head my have no idea what is wrong. Any suggestions?

Upvotes: 0

Views: 348

Answers (1)

Paulw11
Paulw11

Reputation: 114975

Although the type LoginResponse inherits from CodabilityResponse and you can therefore return an instance of the former where the latter is specified, it is the type of the completion handler that is the issue.

The type of the completion handler is (CodabilityResponse)-> Void which can't be downcast from the unrelated type (LoginResponse) -> Void

Instead of

static func login(loginData: LoginRequest, completion: @escaping (LoginResponse) -> Void)

Use

static func login(loginData: LoginRequest, completion: @escaping CompletionHandler)

That way completion is of the correct type and since LoginResponse inherits from CodabilityResponse you can pass an instance of it to commonCompletion

Upvotes: 1

Related Questions