Benjamin RD
Benjamin RD

Reputation: 12034

Migrating generic function from Alamofire 3 to Alamofire 4

I'm migrating this code with Alamofire 3 to Alamofire 4. The reference is: Creating a generic method with AlamoFire in Swift

I have this class:

import Foundation
import Alamofire
import AlamofireObjectMapper
import ObjectMapper

class HttpHandler {

    static func sendRequest<T:BaseUser>(url: String, parameters: [String: AnyObject]?) -> T {
        let res : T
        Alamofire.request(url)
            .validate()
            .responseObject { (response: DataResponse<[T]>) in
                switch response.result {
                case .Success(let value):
                    res.valueHandle?(value)
                case .Failure(let error):
                    res.errorHandle?(error)
                }
        }

        return res
    }
}


class BaseUser: ResponseObjectSerializable {
    var valueHandle : ((BaseUser)->())?
    var errorHandle : ((NSError)->())?

    required init?(response: HTTPURLResponse, representation: AnyObject) {

    }
}

public protocol ResponseObjectSerializable {
    init?(response: HTTPURLResponse, representation: AnyObject)
}

But, I'm getting this error:

Cannot convert value of type '(DataResponse<[T]>) -> ()' to expected argument type '(DataResponse<_>) -> Void'

How I can fix it?

Upvotes: 1

Views: 683

Answers (1)

Sandeep
Sandeep

Reputation: 21144

You are returning from asynchronous method, and expecting that the result is valid, I think you should rethink your implementation of sendRequest method a bit. You can make it such that it takes in completion closure.

Also, your BaseUser does not seem to be a model class, it rather seems like some handler class, so to say. It only has two properties which are closure, what are you trying to map from http request. Should it have some real attributes.

With that, if you have a pure model class and a proper send method, you can achieve what you are trying pretty easily.

The error in your case is because you are using, AlamofireObjectMapper and trying to map values without actually implementing protocol.

Look at the signature of the method,

public func responseObject<T>(queue: DispatchQueue? = default, 
                              keyPath: String? = default, 
                              mapToObject object: T? = default,
                              context: MapContext? = default,
                              completionHandler: @escaping(Alamofire.DataResponse<T>) -> Swift.Void) -> Self where T : BaseMappable

Here the generic parameter T is expected to be of type BaseMapper. If you conform to the protocol Mappable from ObjectMapper, it should be just fine.

class BaseUser: BaseMappable {

    func mapping(map: Map) {
        // map your actual properties here
        // like username, name
    }
}

I have also changed your sendRequest method a bit, such that instead of returning values, it does the request and does a callback after finishing.

static func sendRequest<T:BaseUser>(url: String,
                                    parameters: [String: AnyObject]?,
                                    completion: @escaping ([T], Error?) -> Void) {
    Alamofire.request(url)
        .validate()
        .responseObject { (response: DataResponse<[T]>) in

            switch response.result {
            case .success(let value):
                completion(value, nil)
            case .failure(let error):
                completion([], error)
            }
    }

}

The code looks fine, but it does not yet work. You are expecting that your response to be mapped to array of BaseUser, but AlamofireObjectMapper, expect it to be of type, Mappable.

Now you can use extension to array and conform to the protocol. We can make use of Swift 4.1 Conditional Conformance here.

extension Array: BaseMappable where Element: BaseMappable {

    public mutating func mapping(map: Map) {
        var userHolder: [BaseUser] = []
        // map array of values to your BaseUser
    }
}

And with this you are good to go. Note, that I showed you how the problem that you had could be solved. I also did some small refactoring just to make code more clearer.

Please make changes according to your need.

Upvotes: 2

Related Questions