Swift-自动引用计数

//: Playground - noun: a place where people can play

import UIKit

var str = "Hello, playground"


/*
 Swift 使用自动引用计数(ARC)机制来跟踪和管理你的应用程序的内存。通常情况下,Swift 的内存管理机制会一直起着作用,你无须自己来考虑内存的管理。ARC 会在类的实例不再被使用时,自动释放其占用的内存。
 
 然而,在少数情况下,ARC 为了能帮助你管理内存,需要更多的关于你的代码之间关系的信息。本章描述了这些情况,并且为你示范怎样启用 ARC 来管理你的应用程序的内存。
 
 注意:
 引用计数仅仅应用于类的实例。结构体和枚举类型是值类型,不是引用类型,也不是通过引用的方式存储和传递。
 */

//无主引用
/*
 和弱引用类似,无主引用不会牢牢保持住引用的实例。和弱引用不同的是,无主引用是永远有值的。因此,无主引用总是被定义为非可选类型(non-optional type)。你可以在声明属性或者变量时,在前面加上关键字unowned表示这是一个无主引用。
 
 由于无主引用是非可选类型,你不需要在使用它的时候将它展开。无主引用总是可以被直接访问。不过 ARC 无法在实例被销毁后将无主引用设为nil,因为非可选类型的变量不允许被赋值为nil。
 
 注意:
 如果你试图在实例被销毁后,访问该实例的无主引用,会触发运行时错误。使用无主引用,你必须确保引用始终指向一个未销毁的实例。
 还需要注意的是如果你试图访问实例已经被销毁的无主引用,Swift 确保程序会直接崩溃,而不会发生无法预期的行为。所以你应当避免这样的事情发生。
 */
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") }
}
//注意: CreditCard类的number属性被定义为UInt64类型而不是Int类型,以确保number属性的存储量在32位和64位系统上都能足够容纳16位的卡号。



//无主引用以及隐式解析可选属性
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
    }
}



/*
 HTMLElement类定义了一个name属性来表示这个元素的名称,例如代表段落的"p",或者代表换行的"br"。HTMLElement还定义了一个可选属性text,用来设置和展现 HTML 元素的文本。
 
 除了上面的两个属性,HTMLElement还定义了一个lazy属性asHTML。这个属性引用了一个将name和text组合成 HTML 字符串片段的闭包。该属性是Void -> String类型,或者可以理解为“一个没有参数,返回String的函数”。
 
 默认情况下,闭包赋值给了asHTML属性,这个闭包返回一个代表 HTML 标签的字符串。如果text值存在,该标签就包含可选值text;如果text不存在,该标签就不包含文本。对于段落元素,根据text是"some text"还是nil,闭包会返回"

some text

"或者"

"。 可以像实例方法那样去命名、使用asHTML属性。然而,由于asHTML是闭包而不是实例方法,如果你想改变特定元素的 HTML 处理的话,可以用自定义的闭包来取代默认值。 注意: asHTML声明为lazy属性,因为只有当元素确实需要处理为HTML输出的字符串时,才需要使用asHTML。也就是说,在默认的闭包中可以使用self,因为只有当初始化完成以及self确实存在后,才能访问lazy属性。 HTMLElement类只提供一个构造函数,通过name和text(如果有的话)参数来初始化一个元素。该类也定义了一个析构函数,当HTMLElement实例被销毁时,打印一条消息。 */ //闭包引起的循环强引用 class HTMLElement { let name: String let text: String? lazy var asHTML: Void -> String = { if let text = self.text { return "<\(self.name)>\(text)" } else { return "<\(self.name) />" } } init(name: String, text: String? = nil) { self.name = name self.text = text } deinit { print("\(name) is being deinitialized") } } var paragraph: HTMLElement? = HTMLElement(name: "p", text: "hello, world") print(paragraph!.asHTML()) //注意HTMLElementdeinitializer中的消息并没有被打印,证明了HTMLElement实例并没有被销毁。 paragraph = nil ; /* 解决闭包引起的循环强引用 在定义闭包时同时定义捕获列表作为闭包的一部分,通过这种方式可以解决闭包和类实例之间的循环强引用。捕获列表定义了闭包体内捕获一个或者多个引用类型的规则。跟解决两个类实例间的循环强引用一样,声明每个捕获的引用为弱引用或无主引用,而不是强引用。应当根据代码关系来决定使用弱引用还是无主引用。 注意: Swift 有如下要求:只要在闭包内使用self的成员,就要用self.someProperty或者self.someMethod(而不只是someProperty或someMethod)。这提醒你可能会一不小心就捕获了self。 */ class SomeClass { //如果闭包有参数列表和返回类型,把捕获列表放在它们前面: lazy var someClosure: (Int, String) -> String = { [unowned self, weak delegate = self.delegate!] (index: Int, stringToProcess: String) -> String in // closure body goes here } //如果闭包没有指明参数列表或者返回类型,即它们会通过上下文推断,那么可以把捕获列表和关键字in放在闭包最开始的地方: lazy var someClosure1: Void -> String = { [unowned self, weak delegate = self.delegate!] in // closure body goes here } } //弱引用和无主引用 /* 在闭包和捕获的实例总是互相引用时并且总是同时销毁时,将闭包内的捕获定义为无主引用。 相反的,在被捕获的引用可能会变为nil时,将闭包内的捕获定义为弱引用。弱引用总是可选类型,并且当引用的实例被销毁后,弱引用的值会自动置为nil。这使我们可以在闭包体内检查它们是否存在。 注意: 如果被捕获的引用绝对不会变为nil,应该用无主引用,而不是弱引用。 */ //前面的HTMLElement例子中,无主引用是正确的解决循环强引用的方法。这样编写HTMLElement类来避免循环强引用: //除了在asHTML闭包中多了一个捕获列表。这里,捕获列表是[unowned self],表示“用无主引用而不是强引用来捕获self”。 class HTMLElement1 { let name: String let text: String? lazy var asHTML: Void -> String = { [unowned self] in if let text = self.text { return "<\(self.name)>\(text)" } else { return "<\(self.name) />" } } init(name: String, text: String? = nil) { self.name = name self.text = text } deinit { print("\(name) is being deinitialized") } }


你可能感兴趣的:(Swift)