I have the a codable object as follows:
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?
}
Here is an example of an incident response when called from the 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
}
}
In SwiftUI, I am trying to display a list of these. So I have an array of these IncidentResponse objects named existingIncidents and then the following:
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())
However, I am unable to use existingIncidents as it is as it does not conform to Identifiable or Hashable (so I can't use the id: /.self workaround) ...
How can I get around this?
I tried to add a UUID into IncidentResponse like this:
struct IncidentResponse: Codable {
let incident: IncidentDetails?
var id = UUID().uuidString
}
However, this is then stopping the object from decoding properly from the API.
CodePudding user response:
Option 1:
Give your IncidentResponse
an ID and then tell it to not try to decode the value:
struct IncidentResponse: Codable, Identifiable {
var id = UUID()
let incident: IncidentDetails?
enum CodingKeys: String, CodingKey {
case incident
}
}
Option 2:
Make incident
and id
non-optional and then use this to get the id:
ForEach(existingIncidents, id: \.incident.id) { incident in
I'll also note that IncidentResponse
seems to be a somewhat meaningless wrapper at this point. When you do your decoding and store the values to existingIncidents
(which you haven't shown), you could probably store them just as [IncidentDetails]
instead. In that case, you just have to make the id
property non-optional on IncidentDetails
and declare it as Identifiable
. For example:
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 { $0.incident }