Swift JSON API部分字段缺失时无数据显示问题排查
Swift JSON解析:部分问答项无数据显示问题
问题描述
我通过Swift的模型与视图从JSON API获取数据,需要展示每个key对应的answer1、answer2、answer3和answer4。但部分key仅包含answer1和answer2(甚至只有answer1),此时这些key的内容完全无法显示。我尝试用if let处理answer3/4,但没有效果。
示例JSON数据
"questiondata": { "1": { "question": "When do you want your plans?", "answer1": { "logo": "sun.and.horizon.circle.fill", "Text": "Tonight" } }, "6": { "question": "Active or Lowkey?", "answer1": { "logo": "figure.seated.side.air.lower", "Text": "Active" }, "answer2": { "logo": "dial.medium.fill", "Text": "Lowkey" } } }
现有Swift代码
ContentView
struct ContentViewdos: View { @StateObject var model = DataManager() var body: some View { VStack { if let qData = model.response?.record.questiondata.data { List(Array(qData.keys), id: \.self) { key in VStack { Text(qData[key]?.answer1.text ?? "no data") Text(qData[key]?.answer2.text ?? "no data") if let answer3 = qData[key]?.answer3 { Text(answer3.text) } if let answer4 = qData[key]?.answer4 { Text(answer4.text) } } } } } .task { await model.loadData() } } }
DataManager
@MainActor class DataManager: ObservableObject { @Published var response: APIResponse? = nil @Published private(set) var length = 0 @Published private(set) var index = 0 @Published private(set) var reachedEnd = false @Published private(set) var answerSelected = false func loadData() async { if let url = URL(string: "https://api.jsonbin.io/v3/b/641f82dcace6f33a22fbec99") { do { let (data, _) = try await URLSession.shared.data(from: url) response = try JSONDecoder().decode(APIResponse.self, from: data) } catch { print(error) } } } }
问题根源分析
- JSON键名不匹配:JSON中答案文本的键是大写的
"Text",但Swift模型中如果直接用text属性(小写)且未通过CodingKeys映射,会导致解析后text值为nil,显示"no data"。 - 模型字段可选性错误:如果
Question模型中的answer2、answer3、answer4被定义为非可选类型(Answer而非Answer?),当JSON中缺少这些字段时,整个Question对象解析失败,不会出现在qData中,导致对应的key完全不显示。 - 视图可选值处理冗余:多次使用
qData[key]?.xxx的可选链,不仅冗余,还可能因某个字段nil导致显示默认文本,影响体验。
解决方案
1. 修正模型结构(关键)
确保模型字段可选性正确,并通过CodingKeys匹配JSON键名:
// 需根据实际API结构调整外层模型 struct APIResponse: Codable { let record: Record } struct Record: Codable { let questiondata: QuestionData } struct QuestionData: Codable { let data: [String: Question] } struct Question: Codable { let question: String let answer1: Answer? let answer2: Answer? let answer3: Answer? let answer4: Answer? } struct Answer: Codable { let logo: String let text: String // 映射JSON中的大写"Text"键到Swift的text属性 enum CodingKeys: String, CodingKey { case logo case text = "Text" } }
2. 优化视图可选值处理
先取出Question对象,再逐个判断答案是否存在,避免冗余可选链:
struct ContentViewdos: View { @StateObject var model = DataManager() var body: some View { VStack { if let qData = model.response?.record.questiondata.data { List(Array(qData.keys), id: \.self) { key in if let question = qData[key] { VStack(alignment: .leading, spacing: 8) { Text(question.question) .font(.headline) if let answer1 = question.answer1 { Text("\(answer1.logo): \(answer1.text)") } if let answer2 = question.answer2 { Text("\(answer2.logo): \(answer2.text)") } if let answer3 = question.answer3 { Text("\(answer3.logo): \(answer3.text)") } if let answer4 = question.answer4 { Text("\(answer4.logo): \(answer4.text)") } } .padding(.vertical, 8) } } } } .task { await model.loadData() } } }
3. 排查解析错误
在DataManager中打印详细解析错误,帮助定位问题:
func loadData() async { if let url = URL(string: "https://api.jsonbin.io/v3/b/641f82dcace6f33a22fbec99") { do { let (data, _) = try await URLSession.shared.data(from: url) response = try JSONDecoder().decode(APIResponse.self, from: data) } catch { print("解析错误:\(error.localizedDescription)") print("错误详情:\(error)") } } }
内容的提问来源于stack exchange,提问作者M. Overby
相关产品推荐
相关产品推荐

