【问题标题】:Alamofire 5 - DataRequest with SwiftyJSON as responseAlamofire 5 - 使用 SwiftyJSON 作为响应的 DataRequest
【发布时间】:2025-12-02 06:15:01
【问题描述】:

在您告诉我对所有模型使用Decodable 之前,您是对的,我正在尝试在客户分配的时间内修复一个项目。将所有模型更改为 Decodable 以及使用模型的所有地方都需要几天时间。

项目拦截调用,将其转为SwiftyJSON,并从 API 返回自定义错误消息。

问题在于 Alamofire 5 不再接受作为 DataRequest 的闭包。所以我需要另一种拦截响应的方法,检查这些自定义错误消息,然后将SwiftyJSON 返回给调用者。所有模型都有一个创建 SwiftyJSON 模型的 init。

模型是什么样的 - 简化:

final public class SomeImage: ResponseCollectionSerializable {
    
    public static func collection(json: JSON) -> [SomeImage] {
        var images = [SomeImage]()
        
        for (_, subJson):(String, JSON) in json["children"] {
            if let image = SomeImage(json: subJson) {
                images.append(image)
            }
        }
        
        return images
    }
    
    init?(json: JSON) {
        
        guard let id = json["attributes"]["id"].string, let name = json["name"].string else {
            return nil
        }
        
        imageURL = json["attributes"]["imageURL"].string
        
        super.init(withId: id, name: name)
    }
    
    // Attributes
    let imageURL: String?
}

关于集合模型的协议:

public protocol ResponseCollectionSerializable {
    static func collection(json: JSON) -> [Self]
}

问题领域:

extension Alamofire.DataRequest {
    
    public func responseCollection<T: ResponseCollectionSerializable>(completionHandler: @escaping (DataResponse<[T], AFError>) -> Void) -> Self {
        let responseSerializer = DataResponseSerializer<[T]> { request, response, data, error in
        // error: Trailing closure passed to parameter of type 'DataPreprocessor' that does not accept a closure

            guard error == nil else {
                return .failure(error!)
            }
            
            let JSONSerializer = DataRequest.jsonResponseSerializer(options: .allowFragments)
            let result = JSONSerializer.serializeResponse(request, response, data, error)
            
            switch result {
            case .success(let value):
                if response != nil  {
                    let json = JSON(value)
                    return .success(T.collection(json: json))
                } else {
                    let failureReason = "Response collection could not be serialized"
                    let userInfo = [NSLocalizedFailureReasonErrorKey: failureReason]
                    let error = NSError(domain: Bundle.main.bundleIdentifier!, code: MyErrorCode.JSONSerializationFailed.rawValue, userInfo: userInfo)
                    return .failure(error) // custom Error
                }
            case .failure(let error):
                return .failure(error) // AFError
        }
        
        return response(responseSerializer: responseSerializer, completionHandler: completionHandler)
    }
}

简单来说,我的问题是如何在 Alamofire 5 中对所有调用运行此拦截代码并返回 SwiftyJSON?

【问题讨论】:

    标签: swift alamofire swift5 swifty-json


    【解决方案1】:

    如果您想创建自定义响应序列化程序,您需要遵守DataResponseSerializerProtocol(或ResponseSerializer,如果您也支持下载)。以下是来自our documentation 的示例:

    struct CommaDelimitedSerializer: ResponseSerializer {
        func serialize(request: URLRequest?, response: HTTPURLResponse?, data: Data?, error: Error?) throws -> [String] {
            // Call the existing StringResponseSerializer to get many behaviors automatically.
            let string = try StringResponseSerializer().serialize(request: request, 
                                                                  response: response, 
                                                                  data: data, 
                                                                  error: error)
            
            return Array(string.split(separator: ","))
        }
    }
    

    然后您可以将它与response(using:) 一起使用,或者创建您自己的DataReqeuest 扩展来创建您之前使用的responseCollection 方法。

    在做任何这些之前,我会改用Decodable 和我们的responseDecodable 方法。没有理由仅仅为了 JSON 解析而自己编写任何代码。

    【讨论】: