来源

 

 

自动引用计数(Automatic Reference Counting)简称ARC

  1. 跟踪内存中的实例被哪些类属性、常量或变量所引用
  2. 在没有类属性、常量或变量引用该类实例时,释放该类实例在内存中所占的空间。

ARC机制最主要的功能是自动回收系统分配给类实例的空间。

 

强引用

什么是强引用环:在两个类实例彼此保持对方的强引用,使得每个实例都使对方保持有效时会发生这种情况。我们称之为强引用环。

 

Swift提供了三种方法来解决强引用

  1. 弱引用(Weak Refresh)
  2. 无主引用(Unowned Refreshce)
  3. 捕获列表(Capture List)

 

三种方法对应的场景:

  • 如果被指向的实例有可能为nil,则使用弱引用
  • 如果被指向的实例不为nil,则使用无主引用
  • 如果在类属性使用闭包时,且闭包体内引用当前实例self 而产生强引用环时,则使用捕获列表

弱引用

关键字weak表明引用为弱引用。

注意:弱引用只能声明为变量类型,因为运行时它的值可能改变。弱引用绝对不能声明为常量。

因为弱引用可以没有值,所以声明弱引用的时候必须是可选类型的。在Swift语言中,推荐用可选类型来作为可能没有值的引用的类型。

class Person { 
    let name: String 
    init(name: String) { self.name = name } 
    var apartment: Apartment? 
    deinit { println("\(name) is being deinitialized") } 
} 
  
class Apartment { 
    let number: Int 
    init(number: Int) { self.number = number } 
    weak var tenant: Person?  // 弱引用
    deinit { println("Apartment #\(number) is being deinitialized") } 
} 

 

无主引用

在属性、变量前添加unowned关键字,可以声明一个无主引用。

class Customer { 
    let name: String 
    var card: CreditCard? 
    init(name: String) { 
        self.name = name 
    } 
  
    deinit { println("\(name) is being deinitialized") 
} 
  
class CreditCard { 
    let number: Int 
    unowned let customer: Customer  // 无主引用
    init(number: Int, customer: Customer) { 
        self.number = number 
        self.customer = customer 
    } 
  
// 析构器 deinit { println(
"Card #\(number) is being deinitialized") }

 

隐式展开的可选属性

在类型结尾处加感叹号(City!),表示为隐式展开的可选类型属性。就是说,capitalCity属性的默认值是nil,不需要展开它的值就可以直接访问。

class Country { 
    let name: String 
    let capitalCity: City! // 隐式展开的可选属性,默认值是nil
    init(name: String, capitalName: String) { 
        self.name = name // capitalCity 在此处默认值nil
        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 
    } 
} 

因为capitalCity默认值是nil,一旦Country的实例在初始化时给name属性赋值后,整个初始化过程就完成了。这代表只要赋值name属性后,Country的初始化函数就能引用并传递隐式的self。所以,当Country的初始化函数在赋值capitalCity时,它也可以将self作为参数传递给City的初始化函数。

综上所述,你可以在一条语句中同时创建Country和City的实例,却不会产生强引用环,并且不需要使用感叹号来展开它的可选值就可以直接访问capitalCity:

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

 

捕获列表

占有列表中的每个元素都是由weak或者unowned关键字和实例的引用,如:

[unowned self] // 无主引用
[weak self] // 弱引用

 

捕获列表放置在闭包参数列表和返回类型之前

@lazy var someClosure: (Int, String) -> String = { 
    [unowned self] (index: Int, stringToProcess: String) -> String in 
    // closure body goes here 
}

如果闭包没有指定参数列表或者返回类型(可以通过上下文推断),那么占有列表放在闭包开始的地方,跟着是关键字in:

@lazy var someClosure: () -> String = { 
    [unowned self] in 
    // closure body goes here 
  
}

 

注意:

  1. 引用计数只应用在类的实例。
  2. 弱引用只能声明为变量类型,因为运行时它的值可能改变。弱引用绝对不能声明为常量
  3. 当实例被销毁后,试图访问该实例的无主引用会触发运行时错误,这样的非法操作会百分百让应用崩溃,不会发生无法预期的行为,你应该避免这种情况。
  4. Swift有如下约束:只要在闭包内使用self的成员,就要用self.someProperty或者self.someMethod(而非只是someProperty或someMethod)。这可以提醒你可能会不小心就占有了self。
  5. 如果占有的引用绝对不会置为nil,应该(unowned)用无主引用,而不是(weak)弱引用。

 

2015-03-24

21:15:57

posted on 2015-03-24 10:00  道无涯  阅读(153)  评论(0编辑  收藏  举报