You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 22:35:49