属性
存储属性
- 结构体和类可以定义存储属性,枚举不可以
- 存储在实例内存中
- 创建结构体和类的实例时,必须为所有存储属性设置一个合适的初始值
延迟存储属性
- 第一次用到的时候才会初始化
- 不能保证线程安全
- 结构体包含一个延迟存储属性时,该结构体的var实例才能访问延迟存储属性,let实例不能访问
计算属性
- 本质就是方法
- 不占用实例内存
- 枚举、结构体和类可以定义计算属性
- 枚举实例的rawValue为只读计算属性
struct Circle {
var radius: Double
var diameter: Double {
set {
radius = newValue / 2
}
get {
radius * 2
}
}
lazy var coler = 20
lazy var borderWidth: Double = {
return 30
}()
}
属性观察器
- 可以给非lazy的var属性添加属性观察器
- 属性观察器和计算属性的功能可以应用到全局变量和局部变量
var padding: Double {
willSet {
print(newValue)
}
didSet {
print(oldValue)
}
}
方法
- 值类型的实例方法如果想要修改实例属性,需要在该方法前加mutating
struct Person {
var age = 10
mutating func passYear() {
age += 1
}
}
@discardableResult
@discardableResult func sum(_ n1: Int, _ n2: Int) -> Int {
n1 + n2
}
sum(1, 2)
下标(subscript)
- 可以给任意类型增加下标功能
- 本质是方法
- 可以没有set方法,但必须有get方法
- 只有get方法时,get可以省略
class Point {
var x = 0.0
var y = 0.0
subscript(index: Int) -> Double {
set {
if index == 0 {
x = newValue
} else if index == 1 {
y = newValue
}
}
get {
if index == 0 {
return x
} else if index == 1 {
return y
}
return 0
}
}
}
var point = Point()
point[0] = 1.1
point[1] = 2.2
print(point.x)
print(point.y)
print(point[0])
print(point[1])
- 结构体作为返回值,想要修改结构体实例属性需要写set方法。而类作为返回值,想要修改类实例属性不需要写set方法
struct Point {
var x = 0
var y = 0
}
class PointManager {
var point = Point()
subscript(index: Int) -> Point {
set {
point = newValue
}
get {
point
}
}
}
var manager = PointManager()
manager[0].x = 2
class Grid {
var data = [
[0, 1, 2],
[3, 4, 5],
[6, 7, 8]
]
subscript(row: Int, column: Int) -> Int {
set {
guard row >= 0 && row < 3 && column >= 0 && column < 3 else {
return
}
data[row][column] = newValue
}
get {
guard row >= 0 && row < 3 && column >= 0 && column < 3 else {
return 0
}
return data[row][column]
}
}
}
继承
- 值类型不支持继承,类可以
- Swift没有规定必须继承一个类,OC的类几乎都要继承NSObject
重写下标、方法
- 子类可以重写父类的下标、方法、属性,要加override关键字
- class修饰的下标、方法可一被子类重写,static修饰的方法、下标不允许被子类重写
重写实例属性
- 属性可以被重写为计算属性,不能重写成存储属性
- 只能重写var属性,不能重写let属性
- 重写的属性名、类型要保持一致
- 子类重写后的属性权限不能小于父类属性权限
重写类型属性
- 被class修饰的计算属性,可以被子类重写
- 被static修饰的属性(存储、计算),不能被子类重写
属性观察器
- 子类中可以给var存储属性增加属性观察器
- 子类中可以给父类计算属性增加属性观察器
final
- 被final修饰的下标、属性、方法禁止被重写
- 被final修饰的类禁止被继承
多态
- Swift的多态实现类似于C++的虚表,编译完成时,类的方法存在类型信息中,调用时直接在类型信息中查找
初始化器
init(parameters) {
statements
}
convenience init(parameters) {
statements
}
初始化器调用准则
- 指定初始化器必须从直系父类调换用初始化器
- 便捷初始化器必须从相同的类调用其它初始化器
- 便捷初始化器最终会调用指定初始化器
两段式初始化
- 初始化所有存储属性
- 外层调用初始化器
- 分配内存给实例,但未初始化
- 指定初始化器确保当前类定义的存储属性都能初始化
- 指定初始化器调用父类指定初始化器,不断向上调用,形成初始化链
- 设置新的存储属性值
- 从顶部初始化器往下,链中每个指定初始化器都可以进一步定制实例
- 初始化器现阶段才能使用self
- 最终,链中任何便捷初始化器都有机会定制实例及使用self
重写初始化器
- 把父类的指定初始化器重写为指定或便捷初始化器时,要加override
- 便捷初始化器不能被子类调用,所以便捷初始化器不会被子类重写
自动继承
- 如果子类没有自定义任何指定初始化器,它会自动继承父类所有的指定初始化器。如果子类自定义了指定初始化器,则父类的指定初始化器不会继承
- 如果子类自动继承或者重写了父类所有的指定初始化器,那么父类的便捷初始化器也会自动继承
required
- 用required修饰指定初始化器,表示其所有子类都必须实现该初始化器
- 如果子类重写了required初始化器,也必须加上required,不用加override
可失败初始化器
- 不可定义类型相同的可失败初始化器和非可失败初始化器
- 可以用init!定义隐式解包的可失败初始化器
- 可失败初始化器可以调用非可失败初始化器,非可失败初始化器调用可失败初始化器需要进行解包
- 可以用一个非可失败初始化器重写一个可失败初始化器,但反过来不行
反初始化器(deinit)
- 类似于C++析构函数,也类似于OC dealloc方法
- 当类的实例对象被释放时,就会调用deinit方法
- deinit方法不接收参数,没有(),不能自行调用
- 先调用子类deinit方法,再调用父类deinit方法