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

Swift Combine解码JSON仅提取contents数组报Invalid top-level type错排查

崩溃根因

你遇到的Invalid top-level type in JSON write崩溃由两个问题共同导致:

  • Future闭包内的回调处理逻辑错误:loadJson返回的是Result<Data, Error>类型,你未做分支判断就直接将整个Result枚举作为成功值传给promise,后续JSONSerialization拿到的是Swift枚举值,不属于JSON序列化支持的合法顶层类型(字典/数组/字符串/数字等),直接触发写入崩溃。
  • 解码目标类型不匹配:接口返回的JSON顶层是对象,对应你定义的Welcome结构体,你直接指定解码[Content]数组类型,不符合JSON结构。
修复步骤

不需要在模型定义层面做特殊配置,直接调整Combine算子链的逻辑即可,同时补全网络请求的边界判断:

  1. 修正fetchShows方法逻辑,删除多余的JSONSerialization中转步骤,直接用接口返回的原始Data解码顶层Welcome结构体,再通过map算子提取contents数组作为最终返回值:
func fetchShows(with query: String) -> AnyPublisher<[Content], Error > {
    
    Future<Data, Error> { promise in
        self.loadJson(withQuery: query) { result in
            // 分支处理Result类型,不要直接透传result
            switch result {
            case .success(let data):
                promise(.success(data))
            case .failure(let error):
                promise(.failure(error))
            }
        }
    }
    // 先解码顶层结构体
    .decode(type: Welcome.self, decoder: jsonDecoder)
    // 提取目标contents数组
    .map(\.contents)
    .eraseToAnyPublisher()
}
  1. 修复loadJson方法里的回调逻辑漏洞,避免错误场景下重复触发回调,补充空数据异常:
let urlSession = URLSession(configuration: .default).dataTask(with: url) { (data, response, error) in
    if let error = error {
        completion(.failure(error))
    } else if let data = data {
        // 加else判断,避免error存在时继续走成功逻辑
        completion(.success(data))
    } else {
        completion(.failure(NSError(domain: "APIManager", code: -1, userInfo: [NSLocalizedDescriptionKey: "接口返回空数据"])))
    }
}
补充说明
  • 你当前配置的keyDecodingStrategy = .convertFromSnakeCase可以正常生效,现有Content、Welcome结构体的属性定义和JSON字段完全匹配,不需要修改。
  • 后续遇到类似“接口返回外层包装结构、仅需要内部某字段”的场景,直接在解码完外层结构后用map算子提取目标字段即可,不需要自定义解码逻辑,维护成本最低。

内容的提问来源于stack exchange,提问作者jat

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 02:18:03