【问题标题】:parsing json any type with Codable使用 Codable 解析任何类型的 json
【发布时间】:2019-11-09 18:34:22
【问题描述】:

如果这个问题被多次回答,我很抱歉,但我正在寻找我自己的特定 json 问题,这就是为什么发布这个,这是我的 json,它是一个通知数组列表,在额外的对象中你可以看到它有合同对象, 现在这个对象正在改变它可以是 json 数组的第二个索引中的活动或反馈我如何制作 Codable 结构来解码这种类型的 json 这是我的结构,我不能在 Codable 中做任何类型

struct Alert: Decodable { var id: Int? var isUnread: Bool? var userId: Int? var message: String? var notificationType: String? var extra: Any?

 "value": [
        {
            "id": 153,
            "is_unread": true,
            "user_id": 3,
            "message": "Contract offered from JohnWick. Click here to see the details.",
            "notification_type": "Contract",
            "extra": {
                "contract": {
                    "id": 477,
                    "likes": 0,
                    "shares": 0,
                    "account_reach": 0.0,
                    "followers": 0,
                    "impressions": 0.0,
                    "description": "Fsafasd",
                    "budget": 0.0,
                    "start_date": null,
                    "end_date": null,
                    "status": "pending",
                    "is_accepted": false,
                    "brand_id": 443,
                    "influencer_id": 3,
                    "proposal_id": 947,
                    "created_at": "2019-11-09T17:40:57.646Z",
                    "updated_at": "2019-11-09T17:40:57.646Z",
                    "contract_fee": 435345.0,
                    "base_fee": 5000.0,
                    "transaction_fee": 43534.5,
                    "total_fee": 483879.5,
                    "infuencer_completed": false,
                    "brand_completed": false,
                    "comments": 0
                }
            }
        },
{
            "id": 152,
            "is_unread": true,
            "user_id": 3,
            "message": "Message from JohnWick. Click here to check your inbox.",
            "notification_type": "Message",
            "extra": {
                "message": {
                    "id": 495,
                    "body": "Uuhvh",
                    "read": false,
                    "conversation_id": 42,
                    "user_id": 3,
                    "created_at": "2019-11-08T13:44:02.055Z",
                    "updated_at": "2019-11-08T13:44:02.055Z"
                }
            }
        },
    ]

如您所见,它可以是消息、活动、合同或反馈,那么我如何使用 CodingKeys Codable 解析或为此建模

【问题讨论】:

    标签: json swift xcode parsing codable


    【解决方案1】:

    一个简单的解决方案是创建一个名为Extra 的结构,它为您拥有的每种情况提供四个可选属性。

    struct Extra: Codable {
        let contract: Contract?
        let message: Message?
        let feedback: Feedback?
        let campaign: Campaign?
    }
    

    只要每个消息、活动、合同和反馈都有固定的响应,那么您应该能够为它们创建符合Codable 的结构。

    【讨论】:

      【解决方案2】:

      你在这里不是指Any。正如您所说,extra 可以是“消息、活动、合同或反馈”。它不能是 UIViewController 或 CBPeripheral。这不是“任何东西”。这是四件事之一。

      "One of X things" 是一个枚举:

      enum Extra {
          case contract(Contract)
          case campaign(Campaign)
          case message(Message)
          case feedback(Feedback)
      }
      

      要使其可解码,我们只需要寻找正确的密钥:

      extension Extra: Decodable {
          enum CodingKeys: CodingKey {
              case contract, campaign, message, feedback
          }
      
          init(from decoder: Decoder) throws {
              let container = try decoder.container(keyedBy: CodingKeys.self)
      
              // Try to decode each thing it could be; throw if nothing matches.
              if let contract = try? container.decode(Contract.self, forKey: .contract) {
                  self = .contract(contract)
              } else if let campaign = try? container.decode(Campaign.self, forKey: .campaign) {
                  self = .campaign(campaign)
              } else if let message = try? container.decode(Message.self, forKey: .message) {
                  self = .message(message)
              } else if let feedback = try? container.decode(Feedback.self, forKey: .feedback) {
                  self = .feedback(feedback)
              } else {
                  throw DecodingError.valueNotFound(Self.self,
                                                    DecodingError.Context(codingPath: container.codingPath,
                                                                          debugDescription: "Could not find extra"))
              }
          }
      }
      

      【讨论】:

        【解决方案3】:

        在这篇文章中,你可以找到一种支持任何类型的可编码方式,因此 JSON 返回 String 或 Int 无关紧要:

        anycodableValue

        【讨论】:

          【解决方案4】:

          这不是Any 类型,你有四种不同但可预测的类型。

          参考 Rob 的回答,如果您将 notificationType 解码为枚举并根据其值解码子类型,则可以摆脱 if - else if 链中的解码尝试

          enum NotificationType : String, Decodable {
              case contract = "Contract", message = "Message",  campaign = "Campaign", feedback = "Feedback"
          }
          
          enum Extra {
              case contract(Contract)
              case campaign(Campaign)
              case message(Message)
              case feedback(Feedback)
          }
          
          struct Alert: Decodable {
              let id: Int
              let isUnread: Bool
              let userId: Int
              let message: String
              let notificationType: NotificationType
              let extra: Extra
              
              private enum CodingKeys : String, CodingKey { case id, isUnread, userId, message, notificationType, extra}
              
              init(from decoder: Decoder) throws {
                  let container = try decoder.container(keyedBy: CodingKeys.self)
                  id = try container.decode(Int.self, forKey: .id)
                  isUnread = try container.decode(Bool.self, forKey: .isUnread)
                  userId = try container.decode(Int.self, forKey: .userId)
                  message = try container.decode(String.self, forKey: .message)
                  notificationType = try container.decode(NotificationType.self, forKey: .notificationType)
                  switch notificationType {
                      case .contract:
                          let contractData = try container.decode([String:Contract].self, forKey: .extra)
                          extra = .contract(contractData[notificationType.rawValue.lowercased()]!)
                      case .campaign:
                          let campaignData = try container.decode([String:Campaign].self, forKey: .extra)
                          extra = .campaign(campaignData[notificationType.rawValue.lowercased()]!)
                      case .message:
                          let messageData = try container.decode([String:Message].self, forKey: .extra)
                          extra = .message(messageData[notificationType.rawValue.lowercased()]!)
                      case .feedback:
                          let feedbackData = try container.decode([String:Feedback].self, forKey: .extra)
                          extra = .feedback(feedbackData[notificationType.rawValue.lowercased()]!)
                  }
              }
          }
          

          【讨论】:

            猜你喜欢
            • 2021-09-05
            • 2020-05-30
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-12-29
            • 2019-07-16
            相关资源
            最近更新 更多