19

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?

thecoolmacdude
  • 2,036
  • 1
  • 23
  • 38
  • 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`. – Jon Shier Jan 20 '22 at 18:12
  • 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. – Larme Jan 20 '22 at 19:02
  • @Larme That was it...I'm not using Codable. Thanks! – thecoolmacdude Jan 21 '22 at 15:58

2 Answers2

31

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
        }
}
Larme
  • 24,190
  • 6
  • 51
  • 81
  • You can copy the context of the `JSONResponseSerializer` which, while deprecated, as not yet been removed, and make your own serializer as well. – Jon Shier Jan 21 '22 at 23:46
  • 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()`... – Larme Jan 22 '22 at 12:13
  • 2
    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. – SmileBot Apr 21 '22 at 23:56
  • 3
    @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. – Larme Apr 23 '22 at 09:03
  • 2
    Thanks, going to use responseData + manual deserialization. That deprecation is really annoying. – algrid Aug 18 '22 at 15:28
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'

Underdog
  • 785
  • 10
  • 21