Swift中JSON解码失败:给定数据非有效JSON问题排查
问题解决:Swift JSONDecoder解码API返回数据失败
问题背景
调用指定API后,使用JSONDecoder解码Dashboardd模型时触发数据损坏错误,提示The given data was not valid JSON。
API调用代码
@State private var receives = [Advertisment]() func loadData() async { guard let url = URL(string: "https://new.demozab.com/armup/api/public/api/dashboard") else{ print("iii") return } var request = URLRequest(url: url) request.setValue("U45GxRbn6NLY9Q3QomfgdWpePAjnlTE7O05wPIXL", forHTTPHeaderField: "Authorization") do{ let (data,_) = try await URLSession.shared.data(from: url) print(data.count) print("\(data)") let decodedResponse = try JSONDecoder().decode(Dashboardd.self, from: data) print("klllll") receives = (decodedResponse.data.advertisments ) print(receives) } catch{ print("\(error)") } }
模型类代码
struct Dashboardd: Codable { let success: Bool let message: String let data: DashboardDataClass } // MARK: - DataClass struct DashboardDataClass: Codable { let quickStats: QuickStats let advertisments: [Advertisment] let receives: [Receive] } // MARK: - Advertisment struct Advertisment: Codable { let id, cryptoCurrencyID, tradeBy: Int let tradeType, location, country, market: String let margin: String let tradePrice: Double let tradeTotal, minTransactionLimit, maxTransactionLimit, totalLimit: Int let totalTradeAmount, cryptoCoinAmountPrice, paymentWindow: Int let paymentMethod, accountDetails, additionalInformation, terms: String let isFeedback, status: Int let createdAt, updatedAt, slug: String enum CodingKeys: String, CodingKey { case id case cryptoCurrencyID case tradeBy case tradeType case location, country, market, margin case tradePrice case tradeTotal case minTransactionLimit case maxTransactionLimit case totalLimit case totalTradeAmount case cryptoCoinAmountPrice case paymentWindow case paymentMethod case accountDetails case additionalInformation case terms case isFeedback case status case createdAt case updatedAt case slug } } // MARK: - QuickStats struct QuickStats: Codable { let buyCnt, sellCnt, openCnt, pendingCnt: Int let completeCnt: Int } // MARK: - Receive struct Receive: Codable { let id, tradeOrderID, senderID, receiverID: Int let isTrustedUser, isDistrustedUser, feedbackScore: Int let message: String let status: Int let createdAt, updatedAt, username: String let image: String enum CodingKeys: String, CodingKey { case id case tradeOrderID case senderID case receiverID case isTrustedUser case isDistrustedUser case feedbackScore case message, status case createdAt case updatedAt case username, image } }
接口返回JSON
{ "success": true, "message": "Dashboard details", "data": { "quickStats": { "buyCnt": 3, "sellCnt": 0, "openCnt": 0, "pendingCnt": 0, "completeCnt": 1 }, "advertisments": [ { "id": 8, "crypto_currency_id": 7, "trade_by": 4, "trade_type": "1", "location": "mdu", "country": "1", "market": "5", "margin": "15", "trade_price": 10, "trade_total": 0, "min_transaction_limit": 1, "max_transaction_limit": 16, "total_limit": 16, "total_trade_amount": 0, "crypto_coin_amount_price": 0, "payment_window": 1, "payment_method": "a", "account_details": "d", "additional_information": "d", "terms": "mm", "is_feedback": 0, "status": 0, "created_at": "2023-02-15", "updated_at": "2023-02-15T05:31:12.000000Z", "slug": "" }, { "id": 5, "crypto_currency_id": 1, "trade_by": 4, "trade_type": "Buy", "location": "demo", "country": "98", "market": "74", "margin": "1.2", "trade_price": 15375.35, "trade_total": 0, "min_transaction_limit": 100, "max_transaction_limit": 1000, "total_limit": 1000, "total_trade_amount": 0, "crypto_coin_amount_price": 0, "payment_window": 15, "payment_method": "1", "account_details": "demo", "additional_information": "demo", "terms": "demo", "is_feedback": 0, "status": 0, "created_at": "2023-01-28", "updated_at": "2023-01-28T14:42:52.000000Z", "slug": "BTC" }, { "id": 4, "crypto_currency_id": 1, "trade_by": 4, "trade_type": "Buy", "location": "demo", "country": "98", "market": "98", "margin": "1.2", "trade_price": 1254583.09, "trade_total": 0, "min_transaction_limit": 10, "max_transaction_limit": 100, "total_limit": 100, "total_trade_amount": 0, "crypto_coin_amount_price": 0, "payment_window": 15, "payment_method": "1", "account_details": "demo", "additional_information": "demo", "terms": "demo", "is_feedback": 0, "status": 0, "created_at": "2023-01-28", "updated_at": "2023-01-28T14:02:46.000000Z", "slug": "BTC" }, { "id": 3, "crypto_currency_id": 3, "trade_by": 4, "trade_type": "Buy", "location": "demo", "country": "22", "market": "102", "margin": "1.2", "trade_price": 0.89, "trade_total": 0, "min_transaction_limit": 10, "max_transaction_limit": 100, "total_limit": 100, "total_trade_amount": 0, "crypto_coin_amount_price": 0, "payment_window": 15, "payment_method": "1", "account_details": "demo", "additional_information": "demo", "terms": "demo", "is_feedback": 0, "status": 0, "created_at": "2023-01-28", "updated_at": "2023-01-28T14:00:59.000000Z", "slug": "BUSD" } ], "receives": [ { "id": 7, "trade_order_id": 11, "sender_id": 4, "receiver_id": 4, "is_trusted_user": 1, "is_distrusted_user": 0, "feedback_score": 4, "message": "test", "status": 1, "created_at": "2023-01-28T14:27:04.000000Z", "updated_at": "2023-02-23T05:23:02.000000Z", "username": "smith", "image": "https://new.demozab.com/armup/api/public//userpanel/images/profile.svg" } ] } }
错误信息
dataCorrupted(Swift.DecodingError.Context(codingPath: [], debugDescription: "The given data was not valid JSON.", underlyingError: Optional(Error Domain=NSCocoaErrorDomain Code=3840 "Invalid value around line 1, column 0." UserInfo={NSDebugDescription=Invalid value around line 1, column 0., })))
解决步骤
1. 修复API请求的使用错误
你创建了带Authorization头的URLRequest,但实际调用时没有使用这个请求,而是直接用了原始URL。这会导致API返回非JSON数据(比如401错误页面),从而触发JSON无效的错误。修改代码:
// 替换data(from: url)为data(for: request) let (data,_) = try await URLSession.shared.data(for: request)
2. 修正模型类的键映射
模型类的CodingKeys没有正确对应JSON中的蛇形命名键(比如模型的cryptoCurrencyID对应JSON的crypto_currency_id),导致解码失败。有两种解决方式:
- 手动设置CodingKeys:给每个驼峰命名的属性添加对应的蛇形键值,示例:
enum CodingKeys: String, CodingKey { case id case cryptoCurrencyID = "crypto_currency_id" case tradeBy = "trade_by" // 其他属性依次补充对应映射 }
- 自动转换键格式:给
JSONDecoder设置keyDecodingStrategy,自动将蛇形键转为驼峰命名,无需手动编写CodingKeys:
let decoder = JSONDecoder() decoder.keyDecodingStrategy = .convertFromSnakeCase let decodedResponse = try decoder.decode(Dashboardd.self, from: data)
3. 可选:添加调试打印
在解码前将返回数据转为字符串打印,方便确认API返回的是否为有效JSON:
if let jsonString = String(data: data, encoding: .utf8) { print("API返回内容:\n\(jsonString)") }
完整修正后的API调用代码
@State private var receives = [Advertisment]() func loadData() async { guard let url = URL(string: "https://new.demozab.com/armup/api/public/api/dashboard") else { print("无效URL") return } var request = URLRequest(url: url) request.setValue("U45GxRbn6NLY9Q3QomfgdWpePAjnlTE7O05wPIXL", forHTTPHeaderField: "Authorization") do { let (data, _) = try await URLSession.shared.data(for: request) // 调试用:打印返回的JSON字符串 if let jsonString = String(data: data, encoding: .utf8) { print("API返回JSON:\n\(jsonString)") } let decoder = JSONDecoder() decoder.keyDecodingStrategy = .convertFromSnakeCase let decodedResponse = try decoder.decode(Dashboardd.self, from: data) receives = decodedResponse.data.advertisments print("解码成功,广告数据:\(receives)") } catch { print("解码错误:\(error)") } }
内容的提问来源于stack exchange,提问作者mohammed ibrahim
相关产品推荐
相关产品推荐

