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

如何解析Scryfall API的JSON数据并获取指定字段?

解决Scryfall API JSON解析问题

我帮你梳理下问题根源,再给出修复后的代码:

首先要明确Scryfall API返回的JSON结构和你当前代码的核心不匹配点:

  • API返回的不是直接的卡片数组,而是一个顶层对象,真正的卡片列表嵌套在data字段里
  • 你定义的Card结构体字段和API返回的字段名/路径不对应(比如cardId对应API的tcgplayer_id,imageUrl藏在image_uris子字典中)

下面是修复后的完整代码,我会标注关键修改点:

1. 修正Card结构体的字段映射

struct Card {
    var cardId: String
    var name: String
    var imageUrl: String
    var text: String
    
    init?(dict: [String: Any]){
        // 关键修改:严格匹配API返回的字段名和层级
        guard let tcgplayerId = dict["tcgplayer_id"] as? Int,
              let name = dict["name"] as? String,
              // 从image_uris子字典中提取art_crop链接
              let imageUris = dict["image_uris"] as? [String: Any],
              let imageUrl = imageUris["art_crop"] as? String,
              // 卡片文本对应API的oracle_text字段
              let text = dict["oracle_text"] as? String else { return nil }
        
        self.cardId = String(tcgplayerId) // tcgplayer_id是Int类型,转成String存储
        self.name = name
        self.imageUrl = imageUrl
        self.text = text
    }
}

2. 修复GetCardResponse的解析逻辑

这里就是你要找的json["data"]逻辑的位置——先解析顶层对象,再提取data数组:

// 完善错误枚举,让错误类型更清晰
enum NetworkError: Error {
    case invalidJson
    case missingDataField
}

struct GetCardResponse{
    let cards: [Card]
    
    init(json: Any) throws {
        // 关键修改:先把JSON转成顶层字典,再取出data字段的卡片数组
        guard let topLevelDict = json as? [String: Any],
              let dataArray = topLevelDict["data"] as? [[String: Any]] else {
            throw NetworkError.missingDataField
        }
        
        var cards = [Card]()
        for dictionary in dataArray {
            if let card = Card(dict: dictionary) {
                cards.append(card)
            }
        }
        self.cards = cards
    }
}

3. 其他适配性调整

把NetworkService和CardNetworkService里的AnyObject改成Any(Swift 3+中JSONSerialization.jsonObject返回的是Any类型,避免类型不匹配问题):

class NetworkService {
    private init() {}
    static let shared = NetworkService()
    func getData(url: URL, completion: @escaping (Any) -> ()) {
        let session = URLSession.shared
        session.dataTask(with: url) { (data, response, error) in
            guard let data = data else { return }
            do {
                let json = try JSONSerialization.jsonObject(with: data, options: [])
                DispatchQueue.main.async {
                    completion(json)
                }
            } catch {
                print(error)
            }
        }.resume()
    }
}

class CardNetworkService{
    private init() {}
    static func getCards(url: String, completion: @escaping(GetCardResponse) -> ()) {
        guard let url = URL(string: url) else { return }
        NetworkService.shared.getData(url: url) { (json) in
            do {
                let response = try GetCardResponse(json: json)
                completion(response)
            } catch {
                print(error)
            }
        }
    }
}

关键说明

  • Scryfall API的返回结构是包含data、total_cards等字段的对象,必须先提取data数组才能遍历卡片
  • 字段映射要严格对应API文档:tcgplayer_id是数字类型,需要转成String;art_crop嵌套在image_uris子字典中;卡片文本一般用oracle_text字段

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 07:19:15