17.2 强引用循环
当两个对象的存储属性互相引用对方的时候,一个对象释放的前提是对方先释放,另一对象释放的前提也是对方先释放,这样就会导致类似于“死锁”的状态,最后谁都不能释放,导致内存泄漏。这种现象就是强引用循环。
假设我们开发一个人力资源管理系统,其中Employee
(员工)与Department
(部门)的关联关系如图17-3所示,Employee
的dept
属性关联到Department
,Department
的manager
(部门领导)属性关联到Employee
。
图 17-3 Employee
与Department
的关联关系
示例代码如下:
class Employee { ①
var no : Int
var name : String
var job : String
var salary : Double
var dept : Department? ②
init(no : Int, name: String, job : String, salary : Double) {
self.no = no
self.name = name
self.job = job
self.salary = salary
println("员工\(name) 已经构造成功。")
}
deinit {
println("员工\(name) 已经析构成功。")
}
}
class Department { ③
var no : Int = 0
var name : String = ""
var manager : Employee? ④
init(no : Int, name: String) {
self.no = no
self.name = name
println("部门\(name) 已经构造成功。")
}
deinit {
println("部门\(name) 已经析构成功。")
}
}
var emp: Employee? ⑤
var dept: Department? ⑥
emp = Employee(no: 7698, name: "Blake", job :"Salesman", salary : 1600) ⑦
dept = Department(no : 30, name: "Sales") ⑧
emp!.dept = dept ⑨
dept!.manager = emp ⑩
emp = nil ⑪
dept = nil ⑫
上述代码第①行定义了员工类Employee
,第②行代码var dept : Department?
声明所在部门的属性,它的类型是Department
可选类型。第③行代码定义了部门类Department
,第④行代码 var manager : Employee?
声明部门领导的属性,它的类型是Employee
可选类型。
第⑤行代码var emp: Employee?
声明Employee
引用类型变量emp
,第⑥行代码var dept: Department?
声明Department
引用类型变量dept
。
第⑦行代码创建Employee
对象并赋值给emp
,emp
与Employee
对象建立强引用关系。第⑧行代码创建Department
对象并赋值给dept
,dept
与Department
对象建立强引用关系。但是此时,emp
和dept
两个对象之间并没有建立关系,它们之间的关系如图17-4所示。
图 17-4 emp
与dept
对象之间没有建立关系
代码第⑨行emp!.dept = dept
将引用变量dept
赋值给Employee
的dept
属性,代码第⑩行dept!.manager = emp
将引用变量emp
赋值给Department
的manager
属性,此时emp
和dept
两个对象就建立了关系。它们之间的关系如图17-5所示。
图 17-5 emp
与dept
对象之间建立关系
如果我们通过第⑪行代码emp = nil
和第⑫行代码dept = nil
断开引用关系,如图17-6所示,但是Employee
对象和Department
对象并没有被释放。这是因为①号引用关系(Employee
对象dept
属性引用Department
对象) 保持Department
对象不被释放。而②号引用关系(Department
对象manager
属性引用Employee
对象)保持Employee
对象不被释放。
图 17-6 emp
和dept
强引用断开
最后Employee
对象和Department
对象都没有被释放,这就是强引用循环,会导致内存泄漏。