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

iOS开发求助:无法将远程JSON解析为[String : [ShopItem]]字典

问题分析与修复方案

你的代码存在几个关键问题:

  • completion调用时机错误:completion()放在了task.resume()之后,网络请求是异步操作,此时请求还未完成就执行了completion,导致外部无法获取到最新数据。
  • 错误处理不当:滥用fatalError()会直接导致程序崩溃,且try?会吞掉解码错误,无法定位解码失败的具体原因。
  • 强制解包风险:results["latest"]!如果JSON中没有"latest"键会直接崩溃,应该用可选绑定处理。

修复后的代码:

struct ShopItem: Codable {
    let category: String
    let name: String
    let price: Int
    let image_url: String
}

public class NetworkHelper {
    var items: [ShopItem] = []
    
    let latestURL = URL(string: "https://run.mocky.io/v3/cc0071a1-f06e-48fa-9e90-b1c2a61eaca7")
    let flashSaleURL = URL(string: "https://run.mocky.io/v3/a9ceeb6e-416d-4352-bde6-2203416576ac")
    
    let urlSession = URLSession.shared
    
    // 修改completion为带Result类型的闭包,传递成功或失败信息
    func downloadLatest(_ completion: @escaping (Result<[ShopItem], Error>) -> Void) {
        guard let latestURL = latestURL else {
            completion(.failure(NSError(domain: "Invalid URL", code: -1, userInfo: nil)))
            return
        }
        
        let task = urlSession.dataTask(with: latestURL) { [weak self] data, response, error in
            // 先处理网络错误
            if let error = error {
                completion(.failure(error))
                return
            }
            
            // 验证响应状态码
            guard let httpResponse = response as? HTTPURLResponse, (200..<300).contains(httpResponse.statusCode) else {
                completion(.failure(NSError(domain: "Invalid response", code: (response as? HTTPURLResponse)?.statusCode ?? -2, userInfo: nil)))
                return
            }
            
            // 验证数据存在
            guard let data = data else {
                completion(.failure(NSError(domain: "No data received", code: -3, userInfo: nil)))
                return
            }
            
            do {
                // 解码JSON
                let results = try JSONDecoder().decode([String: [ShopItem]].self, from: data)
                // 安全获取"latest"对应的数据
                guard let latestItems = results["latest"] else {
                    completion(.failure(NSError(domain: "Missing 'latest' key in JSON", code: -4, userInfo: nil)))
                    return
                }
                self?.items = latestItems
                completion(.success(latestItems))
            } catch {
                // 捕获解码错误,方便调试
                print("解码失败:\(error)")
                completion(.failure(error))
            }
        }
        task.resume()
        // 移除这里的completion调用,放到闭包内部执行
    }
}

使用示例:

let helper = NetworkHelper()
helper.downloadLatest { result in
    switch result {
    case .success(let items):
        print("获取到\(items.count)个商品")
        print(items)
    case .failure(let error):
        print("请求失败:\(error)")
    }
}

内容的提问来源于stack exchange,提问作者максим мартынов

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 22:47:46