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

JSON解析遇序列化错误:无法用字符串下标访问AudiobookJSON类型

修复JSON解析中的下标错误问题

你遇到的错误提示很明确:

Error 1: Cannot subscript a value of type 'AudiobookJSON' (aka Array<Dictionary<String, Any>>) with an index of type 'String'

简单说,你把数组类型的AudiobookJSON当成了单个字典来用字符串下标(比如dictionary["id"])访问,但数组只能用整数下标(比如array[0]),这就是问题的核心。

下面给你两种实用的修复方案,根据你的需求选择:

方案一:用JSONDecoder自动解析(推荐,Swift最佳实践)

既然你已经让Audiobook实现了Codable协议,完全没必要手动写初始化方法来解析字典——JSONDecoder会自动帮你处理所有映射工作,代码更简洁也更安全。

1. 简化Audiobook模型

删掉自定义的init(dictionary:)方法,只保留Codable属性定义即可:

import Foundation

struct Audiobook : Codable {
    let id: Int
    let descricao: String
    let urlImagem: String
}

2. 适配API的JSON结构

我注意到你注释掉了一段解析json["data"]的代码,说明这个API的返回结构可能是外层包含data字段的对象,而不是直接返回数组。如果是这样,你需要新增一个结构体来匹配外层的JSON结构:

// 新增一个结构体匹配API返回的外层结构
struct AudiobookResponse: Codable {
    let data: [Audiobook]
}

然后修改APIClient里的解析代码:

do {
    let response = try JSONDecoder().decode(AudiobookResponse.self, from: unwrappedDAta)
    let posts = response.data
    print(posts)
    completion(posts)
} catch {
    print("Could not get API data. \(error), \(error.localizedDescription)")
}

如果API确实直接返回数组,那你原来的JSONDecoder().decode([Audiobook].self, from: unwrappedDAta)代码是没问题的,只要保留简化后的Audiobook模型就行。

方案二:手动解析字典数组(如果需要手动控制解析逻辑)

如果你不想用Codable,坚持手动处理字典,那需要调整类型定义和初始化逻辑:

1. 修正Audiobook的初始化方法

把初始化方法的参数类型从数组AudiobookJSON改成单个字典[String: Any],同时替换强制解包为更安全的可选绑定+默认值:

import Foundation

struct Audiobook {
    let id: Int
    let descricao: String
    let urlImagem: String
    
    init(dictionary: [String: Any]) {
        // 用可选绑定+默认值替代强制解包,避免字段缺失时崩溃
        self.id = dictionary["id"] as? Int ?? 0
        self.descricao = dictionary["descricao"] as? String ?? ""
        self.urlImagem = dictionary["urlImagem"] as? String ?? ""
    }
}

2. 调整APIClient的解析逻辑

用JSONSerialization解析出字典数组,然后遍历数组逐个创建Audiobook实例:

import Foundation

typealias AudiobookJSON = [[String: Any]]

struct APIClient {
    static func getAudiobooksAPI(completion: @escaping ([Audiobook]?) -> Void) {
        let url = URL(string: "https://alodjinha.herokuapp.com/categoria")
        let session = URLSession.shared
        
        guard let unwrappedURL = url else {
            print("Error unwrapping URL");
            return
        }
        
        let dataTask = session.dataTask(with: unwrappedURL) { (data, response, error) in
            guard let unwrappedData = data else {
                print("Error unwrapping data");
                return
            }
            
            do {
                // 先解析成字典数组
                guard let postsJSON = try JSONSerialization.jsonObject(with: unwrappedData, options: .allowFragments) as? AudiobookJSON else {
                    print("Failed to cast response to AudiobookJSON")
                    completion(nil)
                    return
                }
                // 遍历数组创建Audiobook实例
                let posts = postsJSON.map { Audiobook(dictionary: $0) }
                print(posts)
                completion(posts)
            } catch {
                print("Could not get API data. \(error), \(error.localizedDescription)")
            }
        }
        dataTask.resume()
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 08:05:56