11. init、deinit、可选链、协议、元类型
构造和析构
构造方法
构造方法是一种特殊的方法
一个对象创建完毕后,都需要调用构造方法进行初始化(比如属性的初始化)

验证:init方法是在对象创建完毕的时候调用
回到存储属性
在对象创建的时候,存储属性必须有初始值
两种设置初始值的方法:
在定义属性时为其设置默认值
在构造方法中为属性赋初值
不管在哪赋初值,都是为了保证:对象创建后,存储属性有值
除了没有参数的构造方法,还有自定义的有参数构造方法
构造方法类型
构造方法可以分为两类:
指定构造方法(Designated Constructor)
便利构造方法(Convenience Constructor)
被convenicence修饰的构造方法,被称为便利构造方法

便利构造器不是必须的,也就是你不用便利构造器也没关系
但是,就比如上述例子,你使用便利构造器,就可以只定义name,而age就不需要重复赋值了,确实是便利
- 默认情况下,每一个类都有一个隐私的无参的指定构造方法:
init(){} - 如果一个类定义了一个有参的指定构造方法,就不会自动生成无参的指定构造方法
- 指定构造方法必须调用其直接父类的指定构造方法(除非没有父类)
- 便利构造方法必须调用同一类中定义的其他构造方法(不一定是指定构造)
- 便利构造方法最终必须以调用一个指定构造方法结束

只有便利构造方法才能直接调用当前类中的其他构造方法
也就是说,指定构造方法在当前类中不能直接调用其他指定构造方法
只有指定构造方法才能直接调用其父类的构造方法
也就是说,便利构造方法不能直接调用其父类的构造方法
- 如果父类中只有一个指定构造方法且是无参的,那么,子类的指定构造方法默认会自动调用父类中无参的指定构造方法
- 如果父类中存在有参的指定构造方法,那么,子类的指定构造方法不会自动调用父类的无参的指定构造方法
- 常量只能在父类中初始化
自动继承
- 如果子类没有自定义任何指定初始化器,它会自动继承父类所有的指定初始化器
required
- 用required修饰指定初始化器,表明其所有子类都必须实现该初始化器(通过继承或重写实现)
- 如果子类重写了required初始化器,也必须加上required,不用加override
可失败初始化器
类、结构体、枚举都可以使用init?定义可失败初始化器
就是,通过这种初始化器初始化的对象,可能是nil,也就是初始化完后的对象,是可选项对象
反初始化器(deinit)
deinit叫做反初始化器,类似C++的析构函数、OC中的dealloc方法
当类的实例对象被释放内存时,就会调用实例对象的deinit方法
deinit{}
- deinit不接受任何参数,不能写小括号,不能自行调用
- 父类的deinit能被子类继承
- 子类的deinit实现执行完后,会调用父类的deinit(先子后父)
可选链(Optional Chaining)
- 如果可选项为nil,调用方法、下标、属性失败,结果为nil
- 如果可选项不为nil,调用方法、下标、属性成功,结果会被包装成可选项
- 结果本来就是可选项的,不会进行再次包装

协议(Protocol)
协议可以用来定义方法、属性、下标的声明,协议可以被枚举、结构体、类遵守(多个协议之间用逗号隔开)
一个简单的协议:
protocol Drawable {
//方法
func draw()
//属性
var x: Int {
get set}//可读可写
var y: Int {
get}//只读
//下标
subscript(index: Int) -> Int {
get set}//可读可写
}
- 协议中定义方法时,不能有默认参数值
- 默认情况下,协议中定义的内容必须全部实现(也有办法做到只实现一部分协议)
协议中的属性
- 协议中定义属性时,
必须使用var关键字
如果是只读属性(即只有get函数),在实现的时候,是通过函数逻辑动态计算得到的结果,所以返回值是不确定的)
- 实现协议时的属性权限 >= 协议定义的属性权限
- 协议定义get、set,用var存储属性或者get、set计算属性去实现
- 协议定义get,用任何属性都可以实现
协议中static、class使用
为了保证通用,协议中必须使用static定义类型方法、类型属性、类型下标
class关键字只能用在类里面,而结构体也可以遵守协议,结构体没有class,所以,
涉及到类的,协议中只能使用static
在协议声明的时候,声明类型的时候,必须用static,然而,在实现类型的时候,可以用class也可以用static
区别是:
class允许被子类重写;
static不允许被子类重写
protocol Drawable {
//声明类方法
static func draw()
}
class Size: Drawable {
//使用class修饰类方法
class func draw() {
}
}
class Size1: Size {
//使用class修饰类方法,允许子类重写
override class func draw() {
}
}
class Point: Drawable {
//使用static修饰类方法
static func draw() {
print("Point-draw")
}
}
class Point1: Point {
//使用static修饰类方法,不允许子类重写
//Method does not override any method from its superclass
//override func draw() {}
}
协议中mutating
只有将协议中的实例方法标记为mutating
- 才允许结构体、枚举的具体实现修改自身内存
- 类在实现方法时不用加mutating,枚举、结构体才需要加mutating

协议中init
协议中还可以定义初始化器init
非final类实现时,必须加上required
目的是强制要求遵守协议的类,必须实现init方法
protocol Drawable {
init(x: Int, y: Int)
}
class Point: Drawable

最低0.47元/天 解锁文章
939

被折叠的 条评论
为什么被折叠?



