Swift解码JSON至Struct时出现codingKey未找到问题求助
问题描述
调用新闻API获取到如下JSON响应:
{ "status": "ok", "totalResults": 0, "articles": [ { "title": "United places order for 200 Boeing planes, giving two troubled jets a vote of confidence - CNN", "author": "Chris Isidore", "source": { "Id": "cnn", "Name": "CNN" }, "publishedAt": "2022-12-13T14:33:00Z", "url": "https://www.cnn.com/2022/12/13/business/united-boeing-order/index.html" }, { "title": "November CPI: Inflation rose at annual 7.1% over last year - Yahoo Finance", "author": "Alexandra Semenova", "source": { "Id": null, "Name": "Yahoo Entertainment" }, "publishedAt": "2022-12-13T14:17:04Z", "url": "https://finance.yahoo.com/news/november-cpi-inflation-rises-71-over-last-year-141704528.html" }, { "title": "Gold prices jump higher as U.S. CPI rises 7.1% in November - Kitco NEWS", "author": "http://www.facebook.com/kitconews", "source": { "Id": null, "Name": "Kitco NEWS" }, "publishedAt": "2022-12-13T13:37:00Z", "url": "https://www.kitco.com/news/2022-12-13/prices-jump-higher-as-U-S-CPI-rises-7-1-in-November.html" } ] }
对应的Swift模型结构体:
struct Article: Codable { let articles: [ArticleElement] } // MARK: - ArticleElement struct ArticleElement: Codable { let title: String let author: String? let source: Source let publishedAt: Date let url: String } // MARK: - Source struct Source: Codable { let id: String? let name: String enum CodingKeys: String, CodingKey { case id = "Id" case name = "Name" } }
解码时触发错误:
keyNotFound(CodingKeys(stringValue: "articles", intValue: nil), Swift.DecodingError.Context(codingPath: [], debugDescription: "No value associated with key CodingKeys(stringValue: "articles", intValue: nil) ("articles").", underlyingError: nil))
API调用相关代码:
网络请求函数:
func fetch<T: Decodable>(request: Request, type:T.Type, callback: @escaping (Result<T, Error>)->Void) { var urlComponnets = URLComponents(string: request.baseUrl + request.path) var queryItems:[URLQueryItem] = [] for (k, v) in request.params { queryItems.append( URLQueryItem(name: k, value: v)) } urlComponnets?.queryItems = queryItems let urlsesson = URLSession.shared guard let url = urlComponnets?.url else { return } let urlReuqest = URLRequest(url: url) let dataTask = urlsesson.dataTask(with: urlReuqest) { data, responce, error in let jsonDecoder = JSONDecoder() jsonDecoder.dataDecodingStrategy = .deferredToData do { let responce = try jsonDecoder.decode(type, from: data!) callback(.success(responce)) } catch { callback(.failure(error)) } } dataTask.resume() }
ViewModel中的调用代码:
func getArticles(){ let request = Request(baseUrl:"https://newsapi.org", path:"/v2/top-headlines?country=us&category=business&apiKey=\(ApiKey)", params: [:], type: "GET", header: [:]) networkManager.fetch(request: request, type: Article.self) { result in switch result { case .success(let article): self.articles = article.articles case .failure(let error): print(error) } } } var articles: [ArticleElement] = []
确认JSON包含articles字段,但解码失败,寻求解决方法。
解决方法
1. 修复URL拼接错误
当前Request的path包含完整查询参数,同时fetch函数会重新设置queryItems,导致URL格式无效,服务器返回非预期响应(无articles字段)。
修正Request创建方式,拆分路径和查询参数:
func getArticles(){ let request = Request( baseUrl:"https://newsapi.org", path:"/v2/top-headlines", params: [ "country": "us", "category": "business", "apiKey": ApiKey ], type: "GET", header: [:] ) networkManager.fetch(request: request, type: Article.self) { result in // 原有逻辑 } }
2. 设置日期解码策略
ArticleElement的publishedAt为Date类型,默认解码器无法解析ISO8601格式字符串,需添加日期策略:
let jsonDecoder = JSONDecoder() jsonDecoder.dateDecodingStrategy = .iso8601 // 添加此行
3. 移除强制解包并增加错误处理
直接解包data!会引发崩溃,需先处理错误和空数据,同时可打印返回内容排查问题:
let dataTask = urlsesson.dataTask(with: urlReuqest) { data, response, error in if let error = error { callback(.failure(error)) return } guard let data = data else { callback(.failure(NSError(domain: "NetworkError", code: -1, userInfo: [NSLocalizedDescriptionKey: "无返回数据"]))) return } let jsonDecoder = JSONDecoder() jsonDecoder.dateDecodingStrategy = .iso8601 do { let response = try jsonDecoder.decode(type, from: data) callback(.success(response)) } catch { // 打印返回的JSON字符串排查问题 if let jsonString = String(data: data, encoding: .utf8) { print("返回内容: \(jsonString)") } callback(.failure(error)) } }
内容的提问来源于stack exchange,提问作者SJR5
相关产品推荐
相关产品推荐

