Google Books API部分查询JSON解码失败问题求助
问题原因
Google Books API返回的JSON数据里,部分书籍条目可能缺少VolumeInfo中的某些字段(比如出版商、描述、页数等),但你定义的结构体把这些字段都设成了非可选类型(必须存在)。搜索"hello"时刚好所有返回的书籍都包含所有必填字段,所以解码成功;而"weather"的结果里有缺失字段的条目,直接导致解码失败。
解决方案
1. 把结构体中可能缺失的字段改成可选类型
修改VolumeInfo和ImageLinks,给可能为空的字段加上?:
struct VolumeInfo: Codable { let title: String let authors: [String]? // 部分书籍可能没有作者 let publisher, publishedDate, description: String? let pageCount: Int? let imageLinks: ImageLinks? } struct ImageLinks: Codable { let thumbnail: String? }
2. 修复图片URL的拼接错误
你的URL拼接语法有误,把"\(baseURL)\. (bookID)"改成正确的字符串插值写法:
let urlString = "\(baseURL)\(bookID)&printsec=frontcover&img=1&zoom=1&edge=curl&source=gbs_api"
3. 捕获具体的解码错误(推荐)
把原来吞掉错误的try?换成try,放在do-catch块里,能打印出具体的解码问题,方便调试:
do { let (data, _) = try await URLSession.shared.data(from: url) print("Received Data: \(String(data: data, encoding: .utf8) ?? "Data is empty")") let decodedResponse = try JSONDecoder().decode(Response.self, from: data) results = decodedResponse.items print("Results Count: \(results.count)") } catch { print("Error loading or decoding data: \(error)") }
4. UI中处理可选字段
因为字段变成了可选类型,展示时要处理空值情况,比如:
Text("Authors: \(item.volumeInfo.authors?.joined(separator: ", ") ?? "Unknown")")
完整修改后的代码
import SwiftUI struct Response: Codable { let kind: String let totalItems: Int let items: [Result] } struct Result: Codable, Identifiable { let id: String let etag: String let selfLink: String let volumeInfo: VolumeInfo } struct VolumeInfo: Codable { let title: String let authors: [String]? let publisher, publishedDate, description: String? let pageCount: Int? let imageLinks: ImageLinks? } struct ImageLinks: Codable { let thumbnail: String? } struct IndustryIdentifier: Codable { let type: TypeEnum let identifier: String } enum TypeEnum: String, Codable { case isbn10 = "ISBN_10" case isbn13 = "ISBN_13" } struct BookSearchView: View { @State private var results = [Result]() var body: some View { VStack { List(results) { item in HStack { let baseURL = "https://books.google.com/books/content?id=" let bookID = item.id let urlString = "\(baseURL)\(bookID)&printsec=frontcover&img=1&zoom=1&edge=curl&source=gbs_api" AsyncImage(url: URL(string: urlString)) { phase in switch phase { case .empty: ProgressView() case .success(let image): image.resizable().frame(width: 50, height: 75) case .failure: Image(systemName: "book").frame(width: 50, height: 75) @unknown default: EmptyView() } } VStack(alignment: .leading) { Text(item.volumeInfo.title) .font(.headline) Text("Authors: \(item.volumeInfo.authors?.joined(separator: ", ") ?? "Unknown")") .font(.subheadline) if let publisher = item.volumeInfo.publisher { Text("Publisher: \(publisher)").font(.caption) } Divider() Text("\(item.id)").font(.footnote) } } } .task { await loadData() } } } func loadData() async { guard let url = URL(string: "https://www.googleapis.com/books/v1/volumes?q=weather") else { print("Invalid URL") return } do { let (data, _) = try await URLSession.shared.data(from: url) print("Received Data: \(String(data: data, encoding: .utf8) ?? "Data is empty")") let decodedResponse = try JSONDecoder().decode(Response.self, from: data) results = decodedResponse.items print("Results Count: \(results.count)") } catch { print("Error loading or decoding data: \(error)") } } }
内容的提问来源于stack exchange,提问作者damehero
相关产品推荐
相关产品推荐

