使用Alamofire和JSONDecoder解析iTunes API时无法获取response.data如何解决
问题根因
- 你封装的网络层使用Alamofire的
responseJSON方法处理响应,回调返回的是已经序列化完成的Any类型JSON结果,既不是原始响应Data数据,也不是Alamofire原生Response对象,因此外部接收的response参数不存在.data属性,调用自然失败。 - JSONDecoder解析要求传入原始
Data类型数据,你当前拿到的序列化后字典/数组无法直接输入给JSONDecoder。
调整方案
方案1:修改网络层返回原始Data(更推荐,无额外性能损耗)
第一步:修改AlamofireLayer代码
将responseJSON替换为responseData,直接返回原始响应数据:
import Foundation import Alamofire enum MethodType { case get case post } class AlamofireLayer{ class func requestData(_ type : MethodType, URLString : String, parameters : [String : Any]? = nil, finishedCallback : @escaping (_ result: Data?, _ error: Error?) -> ()) { let method = type == .get ? HTTPMethod.get : HTTPMethod.post Alamofire.AF.request(URLString, method: method, parameters: parameters).responseData { (response) in switch response.result { case .success(let data): finishedCallback(data, nil) break case .failure(let error): finishedCallback(nil, error) break } } } }
第二步:修改协议层与实现层适配新回调
import Foundation import SwiftyJSON protocol NetworkUtil { static func postRequest(URLString: String, parameters : [String : Any]?, callback: @escaping (_ data: Data?, _ error: Error?) -> ()) static func getRequest(URLString: String, parameters : [String : Any]?,callback: @escaping (_ data: Data?, _ error: Error?) -> ()) } class NetworkImpl: NetworkUtil{ static func getRequest(URLString: String, parameters: [String : Any]?, callback: @escaping (Data?, Error?) -> ()) { AlamofireLayer.requestData(MethodType.get, URLString: URLString, parameters: parameters) { data, error in callback(data, error) } } public static func postRequest(URLString: String, parameters: [String : Any]?, callback: @escaping (Data?, Error?) -> ()) { AlamofireLayer.requestData(MethodType.post, URLString: URLString, parameters: parameters) { data, error in callback(data, error) } } }
第三步:修改业务调用代码
let url = "https://itunes.apple.com/search?" NetworkImpl.getRequest(URLString: url, parameters: ["term": searchBar.text!, "entity": "software", "country": "cn", "limit": "200"]) { data, error in guard let data = data, error == nil else { print("请求失败: \(error!)") return } do{ let decoder = JSONDecoder() let newModel = try decoder.decode(NewModel.self, from: data) print("------> \(newModel.resultCount)") } catch { print("解析失败: \(error)") } }
补充:NewModel结构要匹配iTunes API返回格式,示例如下:
struct NewModel: Codable { let resultCount: Int let results: [SoftwareItem] } struct SoftwareItem: Codable { let trackName: String? let artistName: String? // 其他需要的字段自行补充 }
方案2:不改动现有网络层的兼容方案
如果不想修改已封装的网络层逻辑,可以把当前回调拿到的序列化后JSON对象重新转回Data再解析:
let url = "https://itunes.apple.com/search?" NetworkImpl.getRequest(URLString: url, parameters: ["term": searchBar.text!, "entity": "software", "country": "cn", "limit": "200"]) { (response) in do{ // 把Any类型的JSON序列化为Data let jsonData = try JSONSerialization.data(withJSONObject: response) let decoder = JSONDecoder() let newModel = try decoder.decode(NewModel.self, from: jsonData) print("------> \(newModel.resultCount)") } catch { print(error) } }
内容的提问来源于stack exchange,提问作者mcry416
相关产品推荐
相关产品推荐

