SwiftUI - 将 ForEach 与不符合可识别/可散列的绑定数组一起使用

SwiftUI - using ForEach with a Binding array that does not conform to identifiable / hashable

我有一个可编码对象如下:

struct IncidentResponse: Codable {
    let incident: IncidentDetails?
}

struct IncidentDetails: Codable, Identifiable {
    let id: String?
    let reason: IncidentReasonResponse?
    let message: String?
    let startedAt: String?
    let endedAt: String?
}

struct IncidentReasonResponse: Codable, Identifiable {
    let id: String?
    let name: String?
    let code: String?
    let inOp: Bool?
}

这是从 API 调用时的事件响应示例:

{
  "incident": {
    "id": "610aebad8c719475517e9736",
    "user": null,
    "reason": {
      "name": "No aircraft",
      "code": "no-aircraft",
      "inOp": true
    },
    "message": "test this",
    "startedAt": "2021-08-04T19:34:05+0000",
    "endedAt": null
  }
}

在 SwiftUI 中,我试图显示这些列表。所以我有一个名为 existingIncidents 的 IncidentResponse 对象数组,然后是以下内容:

var body: some View {
    List {
        Section(header: Text("Existing incidents")) {
            if let existingIncidents = self.existingIncidents {
                ForEach(existingIncidents) { incident in
                    
                    VStack(alignment: .leading) {
                        HStack {
                            Image.General.incident
                                .foregroundColor(Constants.iconColor)
                            Text(incident.incident?.reason?.name ?? "")
                                .foregroundColor(Constants.textColor)
                                .bold()
                        }
                        Spacer()
                        HStack {
                            Image.General.clock
                                .foregroundColor(Constants.iconColor)
                            Text(incident.incident?.startedAt ?? "No date")
                                .foregroundColor(Constants.textColor)
                        }
                        Spacer()
                        HStack {
                            Image.General.message
                                .foregroundColor(Constants.iconColor)
                            Text(incident.incident?.message ?? "No message")
                                .foregroundColor(Constants.textColor)
                        }
                    }
                }
            }
        }
    }
    .listStyle(PlainListStyle())

但是,我无法按原样使用 existingIncidents,因为它不符合 Identifiable 或 Hashable(因此我无法使用 id: /.self 解决方法)...

我该如何解决这个问题?

我尝试像这样将 UUID 添加到 IncidentResponse 中:

struct IncidentResponse: Codable {
    let incident: IncidentDetails?
    var id = UUID().uuidString
}

但是,这会阻止对象从 API 正确解码。

选项 1:

给你的 IncidentResponse 一个 ID,然后告诉它不要尝试解码值:

struct IncidentResponse: Codable, Identifiable {
    var id = UUID()
    let incident: IncidentDetails?
    
    enum CodingKeys: String, CodingKey {
        case incident
    }
}

选项 2:

使 incidentid 成为非可选的,然后使用它来获取 id:

ForEach(existingIncidents, id: \.incident.id) { incident in

我还会注意到 IncidentResponse 在这一点上似乎是一个毫无意义的包装。当您进行解码并将值存储到 existingIncidents (您尚未显示)时,您可能会像 [IncidentDetails] 一样存储它们。在这种情况下,您只需要在 IncidentDetails 上使 id 属性 成为非可选的并将其声明为 Identifiable。例如:

struct IncidentDetails: Codable, Identifiable {
    let id: String
    let reason: IncidentReasonResponse?
    let message: String?
    let startedAt: String?
    let endedAt: String?
}

//....

let existingIncidentsWrappers : [IncidentResponse] = //...
let existingIncidents : [IncidentDetails] = existingIncidentsWrappers.compactMap { [=12=].incident }