我喜欢对不同类型的数据使用单个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/