Update responseJSON to responseDecodable in Swift
Asked Answered
M

2

21

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?

Moldy answered 20/1, 2022 at 16:20 Comment(3)
You'll want to actually decode your response into a Decodable type and provide that type to responseDecodable. Then update your surrounding methods to use a generic rather than Any.Revenant
Do you use Codable, Swift Feature for decoding JSON? If not, you can still use responseData() and call yourself JSONSerialization.jsonObject(with:options:) on it.Genova
@Genova That was it...I'm not using Codable. Thanks!Moldy
G
38

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
        }
}
Genova answered 21/1, 2022 at 16:24 Comment(5)
You can copy the context of the JSONResponseSerializer which, while deprecated, as not yet been removed, and make your own serializer as well.Revenant
Indeed, but since the question was to prepare for next release and remove deprecated code, using JSONResponseSerializer would be more or less using the author code, since I guess (I didn't check) that's what's under the hood of responseJSON()...Genova
This change actually doesn't make a ton of sense. If you legit need it to convert to a dictionary now you need to do the same thing the old method was doing yourself. What the hell.Avrilavrit
@smileBot Feel free to comment on their repo, I gave the discussion link (which might be closed), but you could open an issue with that.Genova
Thanks, going to use responseData + manual deserialization. That deprecation is really annoying.Jenson
P
5
AF.request(apiURL).responseDecodable(of: User.self) { response in
   switch response.result {
   case let .success(data):
     onSuccess(data)
   case let .failure(error):
     onError(error)
    }
   }

That's my code for 'Alamofire', '~> 5.6.2'

Pisci answered 6/9, 2022 at 14:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.