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

Posted

技术标签:

【中文标题】SwiftUI - 将 ForEach 与不符合可识别/可散列的绑定数组一起使用【英文标题】:SwiftUI - using ForEach with a Binding array that does not conform to identifiable / hashable 【发布时间】:2021-09-28 20:52:15 【问题描述】:

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

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

但是,我无法使用现有事件,因为它不符合 Identifiable 或 Hashable(因此我无法使用 id: /.self 解决方法)...

我该如何解决这个问题?

我尝试将 UUID 添加到 IncidentResponse 中,如下所示:

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

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

【问题讨论】:

您确定IncidentDetails 有一个可选 id 属性,还是一直存在? 我可能可以将其设为非可选 好的——同样,IncidentDetails? 在顶层真的是可选的吗? 再一次,不 - 为了公平起见,我已经在可选选项上进行了 OTT @DevB1 你需要它来解码,但你可以稍后放弃它(见我回答的最后一部分) 【参考方案1】:

选项 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  $0.incident 

【讨论】:

非常感谢 - 我已经实现了第一个选项,并且效果很好。再次感谢:) 当然。如果有帮助,请考虑点赞。

以上是关于SwiftUI - 将 ForEach 与不符合可识别/可散列的绑定数组一起使用的主要内容,如果未能解决你的问题,请参考以下文章

SwiftUI 中按钮操作内的 ForEach 循环?

显示来自 Observable Object SwiftUI 的列表

SwiftUI - 类型“服务”不符合协议“可解码”

SwiftUI 列出单个可选项

SwiftUI:删除行时使用 Array/Index 的 ForEach 崩溃

如何使我的自定义 ViewModifier 仅适用于 SwiftUI 中符合(可识别和视图)的内容/视图?