如何使用Alamofire与Codable解析JSON Lines格式数据?
使用Alamofire + Codable解析JSON Lines并转成数组
当然可以实现!我来一步步教你搞定这个需求,顺便给不熟悉JSON Lines的朋友补个基础。
先搞懂什么是JSON Lines
JSON Lines是一种轻量的文本格式,核心规则很简单:每行单独是一个合法的JSON对象,行与行用换行符分隔,没有外层的数组包裹。举个例子:
{"id":1,"name":"Alice"} {"id":2,"name":"Bob"} {"id":3,"name":"Charlie"}这种格式常用于批量数据导出/传输,但Alamofire默认的JSON序列化器不认它——因为标准JSON要求整个响应是单个合法JSON值(要么是数组,要么是单个对象),而JSON Lines是多行独立的JSON,直接用传统方式解析肯定会失败。
解决方案:自定义JSON Lines响应序列化器
我们需要给Alamofire写一个自定义的解析逻辑,把每行的JSON对象单独解析,最后拼成数组。
第一步:实现JSON Lines解码逻辑
先写一个解码器,负责把原始数据拆分成每行,再逐个解析成目标模型:
import Alamofire struct JSONLinesDecoder { static func decode<T: Decodable>(_ type: [T].Type, from data: Data) throws -> [T] { // 把二进制数据转成字符串,按换行分割成非空的行 guard let rawString = String(data: data, encoding: .utf8) else { throw AFError.responseSerializationFailed(reason: .inputDataNilOrZeroLength) } let jsonLines = rawString.components(separatedBy: .newlines).filter { !$0.trimmingCharacters(in: .whitespaces).isEmpty } // 遍历每行,用系统的JSONDecoder解析成单个模型,最后组合成数组 let decoder = JSONDecoder() return try jsonLines.map { line in guard let lineData = line.data(using: .utf8) else { throw AFError.responseSerializationFailed(reason: .invalidUTF8Data) } return try decoder.decode(T.self, from: lineData) } } }
第二步:给Alamofire扩展自定义响应方法
为了调用方便,我们给Request加个扩展,让它支持直接返回解析好的数组:
extension Request { func responseJSONLines<T: Decodable>(queue: DispatchQueue = .main, completionHandler: @escaping (Result<[T], AFError>) -> Void) -> Self { return response(queue: queue, responseSerializer: DataResponseSerializer { _, response, data, error in // 先处理请求层面的错误 guard let responseData = data, error == nil else { return .failure(error ?? AFError.responseSerializationFailed(reason: .inputDataNilOrZeroLength)) } // 调用上面的解码器解析数据 do { let parsedArray = try JSONLinesDecoder.decode([T].self, from: responseData) return .success(parsedArray) } catch { return .failure(AFError.responseSerializationFailed(reason: .decodingFailed(error: error))) } }, completionHandler: completionHandler) } }
第三步:实际使用示例
假设你有一个用户模型:
struct User: Decodable { let id: Int let name: String }
现在发起请求就可以直接拿到数组了:
AF.request("https://your-api-url.com/users.jsonl") .responseJSONLines { (result: Result<[User], AFError>) in switch result { case .success(let userArray): print("成功解析到\(userArray.count)个用户:\(userArray)") // 这里直接用数组就行 case .failure(let error): print("解析失败:\(error.localizedDescription)") } }
为什么传统方法不行?
再啰嗦一句:Alamofire默认的responseDecodable方法会把整个响应数据当成一个完整的JSON来解析,但JSON Lines是多行独立的JSON,整个内容并不是一个合法的JSON值(没有外层数组/对象包裹),所以直接用传统方式必然会抛出解码错误。我们的自定义逻辑就是把整个响应拆成多行,每行单独解析,最后拼成数组,完美适配JSON Lines的格式。
内容的提问来源于stack exchange,提问作者Nevin Jethmalani
相关产品推荐
相关产品推荐

