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

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)
            }
        }
    }
}

问题根源分析

  1. JSON键名不匹配:JSON中答案文本的键是大写的"Text",但Swift模型中如果直接用text属性(小写)且未通过CodingKeys映射,会导致解析后text值为nil,显示"no data"。
  2. 模型字段可选性错误:如果Question模型中的answer2、answer3、answer4被定义为非可选类型(Answer而非Answer?),当JSON中缺少这些字段时,整个Question对象解析失败,不会出现在qData中,导致对应的key完全不显示。
  3. 视图可选值处理冗余:多次使用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 14:52:26