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 }
Другие вопросы по тегам