SwiftUI - использование ForEach с массивом привязки, который не соответствует идентифицируемому / хешируемому
У меня есть кодируемый объект следующим образом:
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 я пытаюсь отобразить их список. Итак, у меня есть массив этих объектов IncidentResponse с именем existingIncidents, а затем следующие:
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 ответ
Опция 1:
Дайте свой идентификатор, а затем скажите ему, чтобы он не пытался декодировать значение:
struct IncidentResponse: Codable, Identifiable {
var id = UUID()
let incident: IncidentDetails?
enum CodingKeys: String, CodingKey {
case incident
}
}
Вариант 2:
Делать
incident
и необязательный, а затем используйте это, чтобы получить идентификатор:
ForEach(existingIncidents, id: \.incident.id) { incident in
Отмечу также, что
IncidentResponse
на данный момент кажется бессмысленной оберткой. Когда вы делаете свое декодирование и сохраняете значения в
existingIncidents
(который вы не показали), вы, вероятно, могли бы хранить их так же, как
[IncidentDetails]
вместо. В этом случае вам просто нужно сделать
id
свойство необязательное на
IncidentDetails
и объявить это как
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 { $0.incident }