如何解析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
相关产品推荐
相关产品推荐

