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

Swift解析维基API JSON报错:期望解码String却发现数值

问题:维基百科API JSON解析失败(缩略图URL获取报错)

我尝试解析维基百科API返回的JSON数据,返回内容如下:

{"batchcomplete":"","query":{"normalized":[{"from":"canterbury bells","to":"Canterbury bells"}],"redirects":[{"from":"Canterbury bells","to":"Campanula medium"}],"pageids":["5372595"],"pages":{"5372595":{"pageid":5372595,"ns":0,"title":"Campanula medium","extract":"Campanula medium, common name Canterbury bells, is an annual or biennial flowering plant of the genus Campanula, belonging to the family Campanulaceae. In floriography, it represents gratitude, or faith and constancy.","thumbnail":{"source":"https://upload.wikimedia.org/wikipedia/commons/thumb/8/86/Campanulaceae_-_Campanula_medium-4.JPG/500px-Campanulaceae_-_Campanula_medium-4.JPG","width":500,"height":375},"pageimage":"Campanulaceae_-_Campanula_medium-4.JPG"}}}} 

我用以下Swift代码尝试获取缩略图源URL等信息:

数据模型代码

struct FlowerData: Decodable {
    let query: Query
}

struct Query: Decodable {
    let pageids: [String]
    let pages: [String: Pages]
    let normalized: [[String: String]]
}

struct Pages: Decodable {
    let extract: String
    let thumbnail: [String: String]
}

解析代码

func parseJSON(_ flowerData: Data) -> FlowerModel? {
    let decoder = JSONDecoder()
    do {
        let decodedData = try decoder.decode(FlowerData.self, from: flowerData)
        let pageID = decodedData.query.pageids[0]
        let name = decodedData.query.normalized[0]["from"]
        let description = decodedData.query.pages[pageID]?.extract
        let thumbnail = decodedData.query.pages[pageID]?.thumbnail["source"]
        let flower = FlowerModel(flowerName: name!, description: description!, thumbnail: thumbnail!)
        return flower
    } catch {
        delegate?.didFailWithError(error: error)
        return nil
    }
}

运行代码时出现如下错误:

typeMismatch(Swift.String, Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "query", intValue: nil), CodingKeys(stringValue: "pages", intValue: nil), _JSONKey(stringValue: "5372595", intValue: nil), CodingKeys(stringValue: "thumbnail", intValue: nil), _JSONKey(stringValue: "width", intValue: nil)], debugDescription: "Expected to decode String but found a number instead.", underlyingError: nil))

目前名称和描述能正常解析,只有缩略图URL获取失败,请问问题出在哪里?


问题原因与修复方案

错误原因

报错信息明确指出:解析width字段时期望得到字符串,但实际返回的是数字类型。查看返回的JSON可知,thumbnail对象包含三个字段:

  • source:字符串类型(图片URL)
  • width:数字类型(500)
  • height:数字类型(375)

但你在Pages结构体里把thumbnail定义成[String: String],强制所有值按字符串解析,遇到width和height这两个数字时就会出现类型不匹配,导致解析失败。

修复步骤

  1. 创建专门的Thumbnail结构体,替代原来的字典类型,精准匹配JSON字段的类型:
struct FlowerData: Decodable {
    let query: Query
}

struct Query: Decodable {
    let pageids: [String]
    let pages: [String: Pages]
    let normalized: [[String: String]]
}

struct Pages: Decodable {
    let extract: String
    let thumbnail: Thumbnail // 替换为自定义结构体
}

// 新增缩略图结构体,匹配JSON字段类型
struct Thumbnail: Decodable {
    let source: String
    let width: Int
    let height: Int
}
  1. 修改解析代码中获取缩略图URL的方式,直接访问结构体的source属性:
func parseJSON(_ flowerData: Data) -> FlowerModel? {
    let decoder = JSONDecoder()
    do {
        let decodedData = try decoder.decode(FlowerData.self, from: flowerData)
        let pageID = decodedData.query.pageids[0]
        let name = decodedData.query.normalized[0]["from"]
        let description = decodedData.query.pages[pageID]?.extract
        // 直接访问thumbnail的source属性
        let thumbnail = decodedData.query.pages[pageID]?.thumbnail.source
        let flower = FlowerModel(flowerName: name!, description: description!, thumbnail: thumbnail!)
        return flower
    } catch {
        delegate?.didFailWithError(error: error)
        return nil
    }
}

这样修改后,JSON解析时会正确识别width和height为整数类型,source为字符串类型,就能成功获取缩略图URL了。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 15:27:19