Switf入门到精通下
# 07.内存管理和异常
# 目录介绍
- 7.1 自动引用计数
- 7.1.1 ARC功能
- 7.1.2 ARC实例
- 7.1.3 类实例间循环强引用
- 7.1.4 解决循环强引用
- 7.1.5 弱引用实例
- 7.1.6 无主引用实例
- 7.1.7 闭包引起循环强引用
- 7.1.8 弱引用和无主引用
- 8.1 拓展
- 8.1.1 什么是拓展
- 8.1.2 拓展语法
- 8.1.3 拓展属性
- 8.1.4 拓展构造器
- 8.1.5 拓展方法
- 8.1.6 拓展可变实例方法
- 8.2 泛型
- 8.3 协议
- 8.3.1 什么是协议
- 8.3.2 协议语法
- 8.3.3 协议的使用
- 8.3.4 协议的继承
# 7.1.1 ARC 功能
Swift 使用自动引用计数(ARC)这一机制来跟踪和管理应用程序的内存
通常情况下我们不需要去手动释放内存,因为 ARC 会在类的实例不再被使用时,自动释放其占用的内存。
但在有些时候我们还是需要在代码中实现内存管理。
ARC 功能
- 当每次使用 init() 方法创建一个类的新的实例的时候,ARC 会分配一大块内存用来储存实例的信息。
- 内存中会包含实例的类型信息,以及这个实例所有相关属性的值。
- 当实例不再被使用时,ARC 释放实例所占用的内存,并让释放的内存能挪作他用。
- 为了确保使用中的实例不会被销毁,ARC 会跟踪和计算每一个实例正在被多少属性,常量和变量所引用。
- 实例赋值给属性、常量或变量,它们都会创建此实例的强引用,只要强引用还在,实例是不允许被销毁的。
# 7.1.2 ARC实例
来看一个案例
class Person {
let name: String
init(name: String) {
self.name = name
print("\(name) 开始初始化")
}
deinit {
print("\(name) 被析构")
}
}
// 值会被自动初始化为nil,目前还不会引用到Person类的实例
var reference1: Person?
var reference2: Person?
var reference3: Person?
// 创建Person类的新实例
reference1 = Person(name: "Runoob")
//赋值给其他两个变量,该实例又会多出两个强引用
reference2 = reference1
reference3 = reference1
//断开第一个强引用
reference1 = nil
//断开第二个强引用
reference2 = nil
//断开第三个强引用,并调用析构函数
reference3 = nil
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# 7.1.3 类实例间循环强引用
下面展示了一个不经意产生循环强引用的例子。例子定义了两个类:Person和Apartment,用来建模公寓和它其中的居民:
class Person {
let name: String
init(name: String) { self.name = name }
var apartment: Apartment?
deinit { print("\(name) 被析构") }
}
class Apartment {
let number: Int
init(number: Int) { self.number = number }
var tenant: Person?
deinit { print("Apartment #\(number) 被析构") }
}
// 两个变量都被初始化为nil
var runoob: Person?
var number73: Apartment?
// 赋值
runoob = Person(name: "Runoob")
number73 = Apartment(number: 73)
// 意感叹号是用来展开和访问可选变量 runoob 和 number73 中的实例
// 循环强引用被创建
runoob!.apartment = number73
number73!.tenant = runoob
// 断开 runoob 和 number73 变量所持有的强引用时,引用计数并不会降为 0,实例也不会被 ARC 销毁
// 注意,当你把这两个变量设为nil时,没有任何一个析构函数被调用。
// 强引用循环阻止了Person和Apartment类实例的销毁,并在你的应用程序中造成了内存泄漏
runoob = nil
number73 = nil
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# 7.1.4 解决循环强引用
Swift 提供了两种办法用来解决你在使用类的属性时所遇到的循环强引用问题:
- 弱引用
- 无主引用
弱引用和无主引用允许循环引用中的一个实例引用另外一个实例而不保持强引用。这样实例能够互相引用而不产生循环强引用。
对于生命周期中会变为nil的实例使用弱引用。相反的,对于初始化赋值后再也不会被赋值为nil的实例,使用无主引用。
# 7.1.5 弱引用实例
# 7.1.6 无主引用实例
# 8.1 拓展
# 8.1.1 什么是拓展
扩展就是向一个已有的类、结构体或枚举类型添加新功能。
扩展可以对一个类型添加新的功能,但是不能重写已有的功能。Swift 中的扩展可以:
- 添加计算型属性和计算型静态属性
- 定义实例方法和类型方法
- 提供新的构造器
- 定义下标
- 定义和使用新的嵌套类型
- 使一个已有类型符合某个协议
# 8.1.2 拓展语法
扩展声明使用关键字 extension:
extension SomeType {
// 加到SomeType的新功能写到这里
}
2
3
一个扩展可以扩展一个已有类型,使其能够适配一个或多个协议,语法格式如下:
extension SomeType: SomeProtocol, AnotherProctocol {
// 协议实现写到这里
}
2
3
# 8.1.3 拓展属性
扩展可以向已有类型添加计算型实例属性和计算型类型属性。
extension Int {
var add: Int {return self + 100 }
var sub: Int { return self - 10 }
}
let addition = 3.add
print("加法运算后的值:\(addition)")
let subtraction = 120.sub
print("减法运算后的值:\(subtraction)")
2
3
4
5
6
7
8
9
10
# 8.1.4 拓展构造器
扩展可以向已有类型添加新的构造器。
这可以让你扩展其它类型,将你自己的定制类型作为构造器参数,或者提供该类型的原始实现中没有包含的额外初始化选项。
扩展可以向类中添加新的便利构造器 init(),但是它们不能向类中添加新的指定构造器或析构函数 deinit() 。
struct Point {
var x: Int
var y: Int
}
extension Point {
// 添加一个构造器
init(x: Int, y: Int) {
self.x = x
self.y = y
}
}
// 使用拓展中的构造器创建Point实例
let point = Point(x: 10, y: 20)
print(point.x) // 输出: 10
print(point.y) // 输出: 20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
在上面的示例中,我们定义了一个名为Point的结构体,它具有x和y两个整数属性。然后,我们使用拓展为Point添加了一个构造器,该构造器接受x和y作为参数,并将其分配给相应的属性。
# 8.1.5 拓展方法
扩展可以向已有类型添加新的实例方法和类型方法。
struct Point {
var x: Int
var y: Int
}
extension Point {
// 添加一个方法
func printCoordinates() {
print("Coordinates: (\(x), \(y))")
}
}
// 使用拓展中的方法
let point = Point(x: 10, y: 20)
point.printCoordinates() // 输出: Coordinates: (10, 20)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
在上面的示例中,我们定义了一个名为Point的结构体,它具有x和y两个整数属性。然后,我们使用拓展为Point添加了一个名为printCoordinates的方法,该方法用于打印坐标。
通过拓展中的方法,我们可以在Point实例上调用printCoordinates方法,而不需要修改Point结构体的定义。
# 8.1.6 拓展可变实例方法
通过扩展添加的实例方法也可以修改该实例本身。
结构体和枚举类型中修改self或其属性的方法必须将该实例方法标注为mutating,正如来自原始实现的修改方法一样。
下面的例子向 Swift 的 Double 类型添加了一个新的名为 square 的修改方法,来实现一个原始值的平方计算:
extension Double {
mutating func square() {
let pi = 3.1415
self = pi * self * self
}
}
var Trial1 = 3.3
Trial1.square()
print("圆的面积为: \(Trial1)")
var Trial2 = 5.8
Trial2.square()
print("圆的面积为: \(Trial2)")
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 8.3 协议
# 8.3.1 什么是协议
协议规定了用来实现某一特定功能所必需的方法和属性。
任意能够满足协议要求的类型被称为遵循(conform)这个协议。类,结构体或枚举类型都可以遵循协议,并提供具体实现来完成协议定义的方法和功能。
Swift 协议(Protocols)是定义方法、属性和其他要求的蓝图,适用于特定任务或功能。协议可以被类、结构体和枚举采纳,并提供这些需求的具体实现。
协议提供了一种约定,用于定义类型之间的通信和交互方式。
# 8.3.2 协议语法
协议的语法格式如下:
protocol SomeProtocol {
// 这里可以定义协议要求
var someProperty: Int { get set }
func someMethod()
}
2
3
4
5
SomeProtocol 定义了一个可读写的属性 someProperty 和一个方法 someMethod。
# 8.3.3 协议的使用
类实现协议,让它遵循MyProtocol协议。我们实现了name属性和sayHello()方法。
class MyClass: MyProtocol {
var name: String = ""
func sayHello() {
print("Hello, \(name)!")
}
}
2
3
4
5
6
7
使用协议,创建了一个MyProtocol类型的变量obj,并将其赋值为MyClass的实例。我们可以通过obj访问name属性和sayHello()方法。
let obj: MyProtocol = MyClass()
obj.name = "John"
obj.sayHello() // 输出:Hello, John!
2
3
# 8.3.4 协议的继承
https://github.com/Liaoworking/Advanced-Swift
swift纯代码开发学习(foundation、UIKit等)
https://github.com/potato512/SYSwiftLearning