ios - 具有不同类型 JSON 数据的通用 UITableViewCell

标签 ios swift

我喜欢对不同类型的数据使用单个tableViewCell实例(而不是创建单独的单元格);通过为此创建一个协议(protocol),使用了一种简单的通用方法,但是如何以清晰的方式从 JSON 填充数据(通过避免 switch-case)?

protocol CellData {
    var title: String { get set }
    var subTitle: String { get set }
    var image: String { get set }
}

对于单个Cell

@IBOutlet weak var titleLabel: UILabel!
@IBOutlet weak var subTitleLabel: UILabel!
@IBOutlet weak var imageView: UIImageView!
{
  "data": [
    {
      "type": "company",
      "data": {
        "name": "Google",
        "sector": "IT",
        "logo": "https://www.google.com/logos/doodles/2015/googles-new-logo-5078286822539264.3-hp2x.gif"
      }
    },
    {
      "type": "person",
      "data": {
        "name": "Bill Gates",
        "occupation": "Microsoft CEO",
        "picture": "https://img.etimg.com/thumb/msid-66398917,width-640,resizemode-4,imgsize-702055/words-of-wisdom.jpg"
      }
    },
    {
      "type": "song",
      "data": {
        "name": "Beat It",
        "singer": "M.Jackson",
        "thumbnail": "https://cdn.smehost.net/michaeljacksoncom-uslegacyprod/wp-content/uploads/2019/08/Sept2019Mobile.jpg"
      }
    },
    {
      "type": "vehicle",
      "data": {
        "name": "Silver Silver",
        "brand": "Silver",
        "photo": "https://images.pexels.com/photos/112460/pexels-photo-112460.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500"
      }
    }
  ],
  "error": null
}

最佳答案

如果您对预期的 key 有保证,那么您可以尝试解析找到的第一个 key 的数据:

struct CellDataEnvelope: Decodable {
  let data: CellData
  let type: CellDataType

  enum CellDataType: String, Decodable {
    case company
    case person
    case song
    case vehicle
  }
}

struct CellData: Decodable {
  let title: String
  let subTitle: String
  let image: String

  enum CodingKeys: CodingKey {
    // title
    case name

    // subTitle
    case sector
    case occupation
    case singer
    case brand

    // image
    case thumbnail
    case picture
    case logo
    case photo
  }
}

extension CellData {
  init(from decoder: Decoder) throws {
    let container = try decoder.container(keyedBy: CodingKeys.self)

    self.title = try container.decode(String.self, forKey: .name)

    self.subTitle = try tryDecodeString(in: container, keys: [.sector, .occupation, .singer, .brand])
    self.image = try tryDecodeString(in: container, keys: [.thumbnail, .picture, .logo, .photo])
  }
}

// Attempts to decode a String value from an array of keys, returns the first one to successfully decode.
private func tryDecodeString(
  in container: KeyedDecodingContainer<CellData.CodingKeys>,
  keys: [CellData.CodingKeys]
) throws -> String {
  for key in keys {
    if let value = try? container.decode(String.self, forKey: key) {
      return value
    }
  }

  throw DecodingError.dataCorrupted(
    .init(
      codingPath: [],
      debugDescription: "Invalid data"
    )
  )
}


let models = try JSONDecoder().decode([CellDataEnvelope].self, from: Data(json.utf8))

如果 key 列表大幅增长或者您对它们没有保证,这可能会变得难以处理。

关于ios - 具有不同类型 JSON 数据的通用 UITableViewCell,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58240249/

相关文章:

ios - 检查具有可达性的网络连接 - IsWWAN 标志始终为 'false'

ios - 为什么来自 parse.com 的推送只能到达一台设备?

ios - 当两个 ViewController 打开时,如何在两个 ViewController 中接收相同的回调?

ios - 大量本地通知swift 3

ios - iOS 5 是否支持 "Use Base Internationalization"?

objective-c - 应用验证失败 : Unable to create Configuration directory:/user/username/. itmstransporter

ios - 我是否可以测试 Flash CS5 iOS 发布的 SWF 或 ipa,而不必每次都将它们加载到 iPhone 上?

iOS Swift - 从选定的 TableView 单元格获取背景颜色

ios - Swift 中的服务定位器模式

ios - 修改按分段控件排序的 TableView 单元格编辑