架构
接口模型不要直接拿去画界面
解码用的结构和 cell 用的结构分开。接口一改,不会把整个界面一起改掉。
把接口 JSON 解码出来的类型直接塞给 cell,一开始省事。字段一改名、可空一变、多一个只给别的端用的嵌套,界面文件就跟着动。列表还会为了凑一个展示字符串去读三层可选值。
两种类型
解码类型靠近接口,字段和后端一致,可空就如实可空。界面类型靠近展示:标题、副标题、是否显示角标,都是已经决定好的值。中间一次映射,把空值、默认文案、日期格式处理掉。
struct ItemDTO: Decodable {
var id: String
var title: String?
var unread: Int?
}
struct ItemRow: Equatable {
var id: String
var title: String
var showsBadge: Bool
}
extension ItemDTO {
func row() -> ItemRow? {
guard !id.isEmpty else { return nil }
let title = title?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
return ItemRow(
id: id,
title: title.isEmpty ? "未命名" : title,
showsBadge: (unread ?? 0) > 0
)
}
}
映射失败就丢掉这一条,或者收成一个明确的失败,不要让 cell 里到处写 ??。id 为空的数据无法复用、无法跳转,不该进列表。
放在哪一层
映射放在功能模块里,不放在 UIView 里,也不放在通用网络库里。网络库不知道“未命名”这个产品决定。界面不应该知道 unread 这个字段名。这样换接口版本时,改映射即可,cell 的入参保持稳定。