解决类实例之间的循环强引用

<aside> 💟 当一个实例的生命周期较短,或者互相引用的两个实例都可被置空时,对其引用可以使用弱引用,而当一个实例的生命周期较长,即使引用它的实例都销毁了它仍然存在,或者一个可以被置空而另一个不可时,使用无主引用。

</aside>

弱引用

<aside> 🌟 因为被弱引用的实例可能会被 ARC 置空,所以声明时一般要用变量,且为可选项。

</aside>

<aside> 🌰 当弱引用被 ARC 置空时,属性观察器不会被触发。

</aside>

/**
 弱引用
 */
class Person {
    let name: String
    init(name: String) { self.name = name }
    var apartment: Apartment?
    deinit { print("\\(name) is being deinitialized") }
}

class Apartment {
    let unit: String
    init(unit: String) { self.unit = unit }
    weak var tenant: Person?
    deinit { print("Apartment \\(unit) is being deinitialized") }
}

var john: Person?
var unit4A: Apartment?

john = Person(name: "John Appleseed")
unit4A = Apartment(unit: "4A")

john!.apartment = unit4A
unit4A!.tenant = john

john = nil
// 打印“John Appleseed is being deinitialized”

unit4A = nil
// 打印“Apartment 4A is being deinitialized”

无主引用

/**
 无主引用
 */
var greeting = "Hello, playground"

class Customer {
    let name: String
    var card: CreditCard?
    init(name: String) {
        self.name = name
    }
    deinit { print("\\(name) is being deinitialized") }
}

class CreditCard {
    let number: UInt64
    unowned let customer: Customer
    init(number: UInt64, customer: Customer) {
        self.number = number
        self.customer = customer
    }
    deinit { print("Card #\\(number) is being deinitialized") }
}

var john2: Customer?
john2 = Customer(name: "John2 Appleseed")
john2!.card = CreditCard(number: 1234_5678_9012_3456, customer: john2!)
john2 = nil
// 打印“John Appleseed is being deinitialized”
// 打印“Card #1234567890123456 is being deinitialized”

无主可选引用

<aside> 🧀 可选类型 Optional 是一个枚举,虽然如枚举、结构体这样的值类型不能被标记为 unowned,因为自动引用计数是针对引用类型的内存管理,但是可选类型是个例外。 且可选值内包装的类不使用自动引用计数,所以不需要维持对可选值的强引用。

</aside>

class Department {
    var name: String
    var courses: [Course]
    init(name: String) {
        self.name = name
        self.courses = []
    }
}

class Course {
    var name: String
    unowned var department: Department
    unowned var nextCourse: Course?
    init(name: String, in department: Department) {
        self.name = name
        self.department = department
        self.nextCourse = nil
    }
}

let department = Department(name: "Horticulture")

let intro = Course(name: "Survey of Plants", in: department)
let intermediate = Course(name: "Growing Common Herbs", in: department)
let advanced = Course(name: "Caring for Tropical Plants", in: department)

intro.nextCourse = intermediate
intermediate.nextCourse = advanced
department.courses = [intro, intermediate, advanced]

无主引用和隐式解包可选项属性

<aside> 🥞 当相互引用的两个实例都不可为空时,一个类使用无主引用声明另一个类,另一个类使用隐式解包可选项的方式引用前一个类。

</aside>

class Country {
    let name: String
    var capitalCity: City!
    init(name: String, capitalName: String) {
        self.name = name
        self.capitalCity = City(name: capitalName, country: self)
    }
}

class City {
    let name: String
    unowned let country: Country
    init(name: String, country: Country) {
        self.name = name
        self.country = country
    }
}

var country = Country(name: "Canada", capitalName: "Ottawa")
print("\\(country.name)'s capital city is called \\(country.capitalCity.name)")
// 打印“Canada's capital city is called Ottawa”