Search code examples
swiftalamofiredecodable

Trailing closure passed to parameter of type 'Set<HTTPMethod>' that does not accept a closure


Was reviewing my colleague code and this error appears.

Any ideas what's wrong with it? Was trying to Run the build and unfortunately this error appears

Error -> Trailing closure passed to parameter of type 'Set<HTTPMethod>' that does not accept a closure

Was trying to change it on DataResponseSerializer<T> doesn't work out for me

Error line -> let responseSerializer = DataResponseSerializer { (request, response, data, error) in

Code here

import Foundation
import Alamofire

extension DataRequest {
    /// @Returns - DataRequest
    /// completionHandler handles JSON Object T
    /// - Returns: `DataRequest`
    @discardableResult func responseObject<T: Decodable> (
        queue: DispatchQueue? = nil,
        _ type: T.Type,
        completionHandler: @escaping (AFDataResponse<T>) -> Void
        ) -> Self {
        
        let responseSerializer = DataResponseSerializer { (_, response, data, error) in
            if let err = error {
                return .failure(err)
            }
            
            let result = DataRequest.serializeResponseData(response: response, data: data, error: error)
            let jsonData: Data
            switch result {
            case .failure(let error):
                return .failure(error)
            case .success(let data):
                jsonData = data
            }
            
            // (1)- Json Decoder. Decodes the data object into expected type T
            // throws error when failes
            let decoder = JSONCoders.snakeCaseDecoder
            do {
                let decoded = try decoder.decode(T.self, from: jsonData)
                return .success(decoded)
            } catch let error {
                return .failure(error)
            }
        }
        
        return response(queue: queue, responseSerializer: responseSerializer, completionHandler: completionHandler)
    }
}

EDIT1:

Error still appears it pointing me out specifically on this bracket - DataResponseSerializer { that something wrong with it. I already try to delete them/add new ones. No idea what's the problem here. I cannot run build cause of this error currently.

This is definition of DataResponseSerializer

/// A `ResponseSerializer` that performs minimal response checking and returns any response data as-is. By default, a
/// request returning `nil` or no data is considered an error. However, if the response is has a status code valid for
/// empty responses (`204`, `205`), then an empty `Data` value is returned.
public final class DataResponseSerializer: ResponseSerializer {
    public let dataPreprocessor: DataPreprocessor
    public let emptyResponseCodes: Set<Int>
    public let emptyRequestMethods: Set<HTTPMethod>

    /// Creates an instance using the provided values.
    ///
    /// - Parameters:
    ///   - dataPreprocessor:    `DataPreprocessor` used to prepare the received `Data` for serialization.
    ///   - emptyResponseCodes:  The HTTP response codes for which empty responses are allowed. `[204, 205]` by default.
    ///   - emptyRequestMethods: The HTTP request methods for which empty responses are allowed. `[.head]` by default.
    public init(dataPreprocessor: DataPreprocessor = DataResponseSerializer.defaultDataPreprocessor,
                emptyResponseCodes: Set<Int> = DataResponseSerializer.defaultEmptyResponseCodes,
                emptyRequestMethods: Set<HTTPMethod> = DataResponseSerializer.defaultEmptyRequestMethods) {
        self.dataPreprocessor = dataPreprocessor
        self.emptyResponseCodes = emptyResponseCodes
        self.emptyRequestMethods = emptyRequestMethods
    }

    public func serialize(request: URLRequest?, response: HTTPURLResponse?, data: Data?, error: Error?) throws -> Data {
        guard error == nil else { throw error! }

        guard var data = data, !data.isEmpty else {
            guard emptyResponseAllowed(forRequest: request, response: response) else {
                throw AFError.responseSerializationFailed(reason: .inputDataNilOrZeroLength)
            }

            return Data()
        }

        data = try dataPreprocessor.preprocess(data)

        return data
    }
}

Solution

  • Alamofire version 5, that you are probably using now, has some breaking changes with the previous versions. The initializer of DataResponseSerializer is no longer getting a closure parameter like Alamofire 4.

    However, you can achieve what are you trying much easier, since Alamofire 5 has already a responseDecodable(of:queue:decoder:completionHandler:) function, in which you can pass in your custom JSONDecoder and make the decoding process for you:

    extension DataRequest {
        /// @Returns - DataRequest
        /// completionHandler handles JSON Object T
        /// - Returns: `DataRequest`
        @discardableResult func responseObject<T: Decodable> (
            queue: DispatchQueue? = nil,
            _ type: T.Type,
            completionHandler: @escaping (AFDataResponse<T>) -> Void
        ) -> Self {
            let decoder = JSONCoders.snakeCaseDecoder
            return responseDecodable(
                of: T.self,
                queue: queue ?? .main,
                decoder: decoder,
                completionHandler: completionHandler
            )
        }
    }
    

    You can even do that without a DataRequest extension directly when you make the request. If let's say you are using a generic function for all your requests, your code might look like this:

    func myGenericRequest<T: Decodable>(url: URL, completionHandler: @escaping (DataResponse<T, AFError>) -> Void) {
        let decoder = JSONCoders.snakeCaseDecoder
        AF.request(url).responseDecodable(decoder: decoder, completionHandler: completionHandler)
    }