Search code examples
iosswiftalamofirejsondecoder

Update responseJSON to responseDecodable in Swift


I'm new to Swift and I'm trying to upgrade some old Swift code. I'm getting the below warning:

'responseJSON(queue:dataPreprocessor:emptyResponseCodes:emptyRequestMethods:options:completionHandler:)' is deprecated: responseJSON deprecated and will be removed in Alamofire 6. Use responseDecodable instead.

...in the below code:

extension Alamofire.DataRequest {
    func json(_ options: JSONSerialization.ReadingOptions = .allowFragments, successHandler: ((Any?) -> Void)? = nil, failureHandler: ((AFDataResponse<Any>) -> Void)? = nil) -> Self {
        return responseJSON() {
            response in
            if UtilityService.ensureSuccessful(response, failureHandler: { failureHandler?(response) }) {
                successHandler?(response.value)
            }
            NetworkActivityManager.sharedInstance.decrementActivityCount()
        }
    }
}

If I replace responseJSON with responseDecodable, I get this error:

Generic parameter 'T' could not be inferred

What do I need to do to update this code?


Solution

  • Alamofire recommends to use responseDecodable() because people were often using responseJSON(), then get the response.data, and call a JSONDecoder() on it. So this was making inner call of JSONSerialization for "nothing". Also, since Codable is "new", and there were still old questions available, people could be missing the Codable feature. See this topic on Alamofire Repo.
    So if you use Codable, I encourage it when possible, use responseDecodable() instead.

    But, you still can do it manually, by retrieving Data with no conversion:

    For that, use:

    @discardableResult func responseData(queue: DispatchQueue = .main, dataPreprocessor: DataPreprocessor = DataResponseSerializer.defaultDataPreprocessor, emptyResponseCodes: Set<Int> = DataResponseSerializer.defaultEmptyResponseCodes, emptyRequestMethods: Set<HTTPMethod> = DataResponseSerializer.defaultEmptyRequestMethods, completionHandler: @escaping (AFDataResponse<Data>) -> Void) -> Self
    

    In use:

    request.responseData { response in
        switch response.result {
            case .success(let data):
                do {
                    let asJSON = try JSONSerialization.jsonObject(with: data)
                    // Handle as previously success
                } catch {
                    // Here, I like to keep a track of error if it occurs, and also print the response data if possible into String with UTF8 encoding
                    // I can't imagine the number of questions on SO where the error is because the API response simply not being a JSON and we end up asking for that "print", so be sure of it
                    print("Error while decoding response: "\(error)" from: \(String(data: data, encoding: .utf8))")
                }
            case .failure(let error):
                // Handle as previously error
            }
    }