一直觉得自己写的不是技术而是情怀一个个的教程是自己这一路走来的痕迹。靠专业技能的成功是最具可复制性的希望我的这条路能让你们少走弯路希望我能帮你们抹去知识的蒙尘希望我能帮你们理清知识的脉络希望未来技术之巅上有你们也有我。文章目录模型转换知识点关于模型的属性设置有三种这3中的写法这3种如何选择这3种的优点和缺点属性带?号赋值使用json解析null, 解析失败如何处理更高级的写法属性包装器如何自定义属性如何对模型进行比较模型转换OC 工具 模型 model Json转Codable (网站使用说明)JSON转SwiftCodable模型生成器-V3.html (工具下载链接)知识点关于模型的属性设置有三种这3中的写法1.var message: String? 表达“可能没有”2.var message: String表达“没有就是空字符串”3.var message: String!必须有否则报错这3种如何选择第一种(建议选择)原因后台返回的数据是null很普片因为后台通过查表的形式返回数据查回来无就是无null,所以前端为了最大宽容的兼容后端保持一致最好属性带号结果保持一致。第二种: 就是如果后台返回null就给属性一个默认值使得属性永远有值。第三种 就是要求属性必须要有值返回不然使用的时候会崩溃这3种的优点和缺点第一种优点能最大宽容兼容后台返回的值不管后台返回啥都能装进去缺点使用的时候需要用可选绑定的方式确保有值才能赋值给属性显示不然会崩或者报错。使用的时候稍微比第二种方式繁琐在下面会详细讲 属性带?号赋值使用第二种优点给属性赋值的时候直接用就可以了不用考虑是否有值的问题因为会给默认值不过这样会带来两个问题不想HandyJson自动处理1.json解析null, 解析失败如何处理下面有讲如何解决2.json返回的字段缺失的处理反过来模型里面某个属性自定义代理的问题 下面有讲如何解决缺点Codable的实现模型里面的写法比较繁琐而且某些地方赋默认值不太合理。例如code 如果给0作为不认值不合理因为后台经常定义code 0 是接口访问成功通常给-1比较合理但是很多Int类型的属性默认值又给0还有枚举或者结构体等也是需要赋默认值。第三种优点没有缺点没值崩溃属性带?号赋值使用tableview DataSource的赋值Cell赋值层层剥壳赋值json解析null, 解析失败如何处理Swift- Json处理null.zip如果属性赋默认值var message: String String(), json解析null, 解析失败如何处理看下面的代码模型全部赋默认值class LoginModel: Codable{var message: StringString()var data: LoginDataModelLoginDataModel()var code: Int0enum CodingKeys: String, CodingKey{casemessagecasedatacasecode}}class LoginDataModel: Codable{var employee: LoginEmployeeModelLoginEmployeeModel()var expiresAt: Int0var user: LoginEmployeeModelLoginEmployeeModel()var isStationStaff: Boolfalsevar token: StringString()var isDriver: Boolfalseenum CodingKeys: String, CodingKey{caseemployeecaseexpiresAtcaseusercaseisStationStaffcasetokencaseisDriver}}class LoginEmployeeModel: Codable{var authority: LoginAuthorityModelLoginAuthorityModel()enum CodingKeys: String, CodingKey{caseauthority}}class LoginAuthorityModel: Codable{var defaultRouter: StringString()var authorityId: Int0var createdAt: StringString()var authorityName: StringString()var updatedAt: StringString()enum CodingKeys: String, CodingKey{casedefaultRoutercaseauthorityIdcasecreatedAtCreatedAtcaseauthorityNamecaseupdatedAtUpdatedAt}}然后son返回的字段全是null{message:null,data:{employee:{authority:{defaultRouter:null,authorityId:null,CreatedAt:null,authorityName:null,UpdatedAt:null}},expiresAt:null,user:{authority:{defaultRouter:null,authorityId:null,CreatedAt:null,authorityName:null,UpdatedAt:null}},isStationStaff:null,token:null,isDriver:null},code:null}调用代码模型转换解析会出现错误Calling provided entry point. 解析JSON数据出错: valueNotFound(Swift.String, Swift.DecodingError.Context(codingPath:[CodingKeys(stringValue:message, intValue: nil)], debugDescription:Expected String value but found null instead., underlyingError: nil))原因是模型定义的属性var message: String String()是不接受null很多人认为如果是null就赋一个默认值实际上null就会类似抛出异常还没来得及赋默认值就炸了。解决办法每个模型实现init(from decoder: Decoder)处理抛出的异常例如class LoginModel: Codable{var message: StringString()var data: LoginDataModelLoginDataModel()var code: Int0enum CodingKeys: String, CodingKey{casemessagecasedatacasecode}requiredinit(){}required init(from decoder: Decoder)throws{letcontainertry decoder.container(keyedBy: CodingKeys.self)messagetry container.decodeIfPresent(String.self, forKey: .message)??datatry container.decodeIfPresent(LoginDataModel.self, forKey: .data)?? LoginDataModel()codetry container.decodeIfPresent(Int.self, forKey: .code)??0}}每个模型都需要写写好之后就算json的字段全是null都没问题,看下面的日志全部接受null的处理更高级的写法属性包装器如果觉得每个模型都实现init(from decoder: Decoder)太麻烦你可以使用属性包装器的方式1.首先封装一个属性包装器2.使用如何自定义属性如何自定义属性json解析数据的时候不影响自定义属性很简单只要实现enum CodingKeys: String, CodingKey就可以在该模型自定义任意属性如何对模型进行比较遵守Equatable协议实现static func 方法