纵然Swift使用ARC(Automatic Reference Counting)为咱们打理内存,这并不表明它面对任何状况都足够聪明。尤为是当对象之间存在相互引用的时候,更是容易因为reference cycle致使内存没法释放。固然,这并不是咱们本意,只是有时这样的问题发生的不甚明显。Swift为咱们提供了一系列语言机制来处理reference cycle,而咱们也应该时刻保持警醒,避免内存泄漏。spa
*“ARC只针对类对象才生效,struct和enum都是值类型,它们的对象并不被ARC管理。”
特别提示*code
Swift使用“引用计数(reference count)”来管理类对象的生命周期,避免类对象在“仍被使用”的时候被意外释放。为了观察reference count、对象构建和对象释放之间的关系,咱们先来定义一个类:视频
class Person { let name: String init(name: String) { self.name = name print("\(name) is being initialized.") } deinit { print("\(name) is being deinitialized.") } }
接下来,咱们观察下面代码的的执行过程:对象
var ref1: Person? var ref2: Person? // Mars is being initialized. // count = 1 ref1 = Person(name: "Mars") // count = 2 ref2 = ref1 // count = 1 ref2 = nil // count = 0 // Mars is being deinitialized. ref1 = nil
Person构造时,init被调用,只有一个变量引用了这个对象,此时的reference count为1;生命周期
当咱们把ref1赋值给ref2时,它们指向相同的对象,此时的reference count为2;内存
当ref2为nil时,此时的reference count恢复为1;文档
当ref1为nil时,reference count为0,Tennat的deinit被调用,对象被释放;get
在上面的例子里,因为ref1和ref2都会致使Person的reference count加1,所以它们叫作 strong reference 。这是Swift中的默认行为。it
*“和带有Garbage Collection的语言不一样,当一个对象的reference count为0时,Swift会当即删除该对象。”
特别提示*
对于Person这样的单个对象,ARC能够很好的默默为咱们工做。可是, 当不一样类对象之间存在相互引用时 ,指向彼此的strong reference就会致使reference cycle。ARC没法释放它们之中的任何一个。来看一个例子,咱们给Person添加一个Apartment:
class Person { let name: String var apartment: Apartment? init(name: String) { self.name = name print("\(name) is being initialized.") } deinit { print("\(name) is being deinitialized.") } } class Apartment { let unit: String var tenant: Person? init(unit: String) { self.unit = unit print("Apartment \(unit) is being initialized.") } deinit { print("Apartment \(unit) is being deinitialized.") } }
因为Person不必定会租Apartment,Apartment也不必定有房客,所以,Person.apartment和Apartment.tenant都是一个Optional,它们能够为nil。
接下来,咱们分别建立一个Person和Apartment对象,而后把变量设置为nil,就能够看到Person和Apartment被构建和销毁了。
// Mars is being initialized // count = 1 var mars: Person? = Person(name: "Mars") // Apartment 11 is being initialized // count = 1 var apt11: Apartment? = Apartment(unit: "11") // count = 0 // Mars is being deinitialized mars = nil // count = 0 // apartment is being deinitialized apt11 = nil
接下来,若是咱们让mars和apartment分别指向彼此:
// ... Create mars and apartment // mars.count = 2 mars!.apartment = apartment // apartment.count = 2 apt11!.tenant = mars // ... Set mars and apartment to nil
这时,尽管咱们把mars和apt11设置为nil,Person和Apartmetn的deinit也不会被调用了。由于它们的两个member(apartment和tenant)是一个strong reference,指向了彼此,让对象仍旧“存活”在内存里。可是,mars和apt11已经被设置成nil,咱们也已经无能为力了。这就是类对象之间的reference cycle。
在理解了ARC的基本工做原理以及reference cycle的成因以后,咱们将在接下来的一些列视频里,了解如何经过weak和unowned reference来解决reference cycle。