17.2 强引用循环
当两个对象的存储属性互相引用对方的时候,一个对象释放的前提是对方先释放,另一对象释放的前提也是对方先释放,这样就会导致类似于“死锁”的状态,最后谁都不能释放,导致内存泄漏。这种现象就是强引用循环。
假设我们开发一个人力资源管理系统,其中Employee(员工)与Department(部门)的关联关系如图17-3所示,Employee的dept属性关联到Department,Department的manager(部门领导)属性关联到Employee。

图 17-3 Employee与Department的关联关系
示例代码如下:
class Employee { ①var no : Intvar name : Stringvar job : Stringvar salary : Doublevar dept : Department? ②init(no : Int, name: String, job : String, salary : Double) {self.no = noself.name = nameself.job = jobself.salary = salaryprintln("员工\(name) 已经构造成功。")}deinit {println("员工\(name) 已经析构成功。")}}class Department { ③var no : Int = 0var name : String = ""var manager : Employee? ④init(no : Int, name: String) {self.no = noself.name = nameprintln("部门\(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对象都没有被释放,这就是强引用循环,会导致内存泄漏。
