本以为之前使用Codable的过程中踩的坑已经够多了,今天博主有遇到一个坑,调了一个下午才解决,问题不大,但是中文的技术文里都很少涉及这个问题。
问题描述:遵循了Codable协议的自定义类,派生出的子类JSON化与反JSON化。
简单来说,就是这儿有一个类遵循了Codable协议,其自身可以很方便地使用JSONEncoder和JSONDecoder来JSON化和反JSON化。但是子类就不是那么方便了。系统提示需要实现一个require init?(from:)的初始化方法。通过这次踩坑,博主总结出了两点在使用Codable的过程中需要注意的点。
首先我们通过一个例子来说明吧。
实现一个Person类,包含属性firstName(姓)、lastName(名)、fullName(全名)、age(年龄)和gender(性别)。gender需要使用枚举类型。包含初始化方法,并且可以使用print直接输出,并可以JSON和反JSON化。
再实现一个Student类,继承自Person,并包含自己的stuNo(学号)和department(公寓)属性。department属性需要使用枚举类型。包含初始化方法,并且可以使用print直接输出,并可以JSON和反JSON化。
看要求两个类需要实现的功能不多且相似,本以为会很简单地解决,但编程就是这么有趣。
首先来实现Person类,我们需要一个性别的枚举
//性别的枚举
enum Gender: Int {
case male //男性
case female //女性
case unknow //未知
}
然后就可以实现Person类了。
//人类
class Person: CustomStringConvertible, Codable {
var firstName: String //姓
var lastName: String //名
var age: Int //年龄
var gender: Gender //性别
var fullName: String { //全名
get {
return firstName + lastName
}
}
//构造方法
init(firstName: String, lastName: String, age: Int, gender: Gender) {
self.firstName = firstName
self.lastName = lastName
self.age = age
self.gender = gender
}
//实现CustomStringConvertible协议中的计算属性,可以使用print直接输出对象内容
var description: String {
return "fullName: \(self.fullName), age: \(self.age), gender: \(self.gender)"
}
}
Person类的实现非常方便,其中的fullName博主选择使用计算属性,因为它与姓和名相关。然后为了可以使用print输出,Person类遵循了CustomStringConvertible协议,读者也可以继承自NSObject去重写其中的description计算属性,看个人爱好。最后为了可以转换为JSON属性,遵循了Codable协议。编译一下代码,系统报错,说Person类没有遵循Codable协议,然后博主就纳闷儿了。尝试了半天,发现如果自定义的类中嵌套了自定义的类、结构体或枚举,使用Codable协议时,这些嵌套的类型也需要遵循Codable协议,所以,解决方法很简单,直接在Gender枚举上遵循Codable协议就好。
更改代码如下: