在关联枚举中使用Codable

场景:在同一个接口中服务器根据不同的status返回不同的json格式。

  1. 服务器返回的json如下:
//1 - user is confirmed:
{
  "status": "confirmed",
  "confirmedUsers": [
    {"id": "abc", "name": "Rachel"},
    {"id": "def", "name": "John"}
  ]
}

//2 - user is in waitlist:
{
  "status": "waitlist",
  "position": 12,
  "confirmedUsers": [
    {"id": "abc", "name": "Rachel"},
    {"id": "def", "name": "John"}
  ]
}

//3 - user cannot go for a different reason
{
  "status": "not allowed",
  "reason": "It is too late to confirm to this event."
}
复制代码
  1. 如何构造model?
  • 不好的做法:
struct EventConfirmationResponse {
  let status: String
  let confirmedUsers: [User]?
  let position: Int?
  let reason: String?
}
复制代码
  • 比较好的做法:
enum EventConfirmationResponse {
  case confirmed([User]) //Contains an array of users going to the event
  case waitlist(Int, [User]) //Contains the position in the waitlist and
  case notAllowed(String) //Contains the reason why the user is not allowed
}
复制代码
  1. 实现Codable
//declare which keys in the JSON we are interested in
enum CodingKeys: String, CodingKey {
    case status
    case confirmedUsers
    case position
    case reason
}

//declare the possible values os the status key
private enum EventConfirmationStatus: String, Codable {
    case confirmed
    case waitlist
    case notAllowed = "not allowed"
}

extension EventConfirmationResponse: Encodable {
  func encode(to encoder: Encoder) throws {
      //access the keyed container
      var container = encoder.container(keyedBy: CodingKeys.self)

      //iterate over self and encode (1) the status and (2) the associated value(s)
      switch self {
      case .confirmed(let users):
          try container.encode(EventConfirmationStatus.confirmed, forKey: .status)
          try container.encode(users, forKey: .confirmedUsers)
      case .waitlist(let position, let users):
          try container.encode(EventConfirmationStatus.waitlist, forKey: .status)
          try container.encode(users, forKey: .confirmedUsers)
          try container.encode(position, forKey: .position)
      case .notAllowed(let reason):
          try container.encode(EventConfirmationStatus.notAllowed, forKey: .status)
          try container.encode(reason, forKey: .reason)
      }
  }
}


extension EventConfirmationResponse: Decodable {
    init(from decoder: Decoder) throws {
        //access the keyed container
        let container = try decoder.container(keyedBy: CodingKeys.self)

        //decode the value for the status key into the EventConfirmationStatus enum
        let status = try container.decode(EventConfirmationStatus.self, forKey: .status)

        //iterate over the received status, and try to decode the other relevant values
        switch status {
        case .confirmed:
            let users = try container.decode([User].self, forKey: .confirmedUsers)
            self = .confirmed(users)
        case .waitlist:
            let users = try container.decode([User].self, forKey: .confirmedUsers)
            let position = try container.decode(Int.self, forKey: .position)
            self = .waitlist(position, users)
        case .notAllowed:
            let reason = try container.decode(String.self, forKey: .reason)
            self = .notAllowed(reason)
        }
    }
}

复制代码

参考资料:
Using Codable to make enums with associated values even more powerful

转载于:https://juejin.im/post/5ceba33ef265da1b8466c35c

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值