//自动引用计数

import UIKit

/*自动引用计数(Automatic Reference Counting)

防止循环强引用

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

自动引用计数的工作机制:ARC会跟踪你所新创建的类的实例的引用数量,只要存在对实例的强引用,该实例就无法被销毁回收内存(类、闭包都是引用类型)

1.当你每次创建一个类的新的实例的时候,ARC 会分配一大块内存用来储存实例的信息。内存中会包含实例的类型信息,以及这个实例所有相关属性的值。

2.此外,当实例不再被使用时,ARC 释放实例所占用的内存,并让释放的内存能挪作他用。这确保了不再被使用的实例不会一直占用内存空间。

3.然而,当 ARC 收回和释放了正在被使用中的实例,该实例的属性和方法将不能再被访问和调用。实际上,如果你试图访问这个实例,你的应用程序很可能会崩溃。

4.为了确保使用中的实例不会被销毁,ARC 会跟踪和计算每一个实例正在被多少属性、常量、变量所引用。哪怕实例的引用数为1,ARC都不会销毁这个实例。

5.为了使上述成为可能,无论你将实例赋值给属性、常量或变量,它们都会创建此实例的强引用。之所以称之为“强”引用,是因为它会将实例牢牢地保持住,只要强引用还在,实例是不允许被销毁的

防止循环强引用:(只要切断所有指向实例的强引用,即使存在弱引用或无主引用,则该实例立即被销毁,同时其内部对其他实例的强引用也一起消失)

1.类实例的强引用数永远不能变成0时,即:如果两个类实例互相持有对方的强引用,因而每个实例都让对方一直存在,从而导致引用计数不能变0,就出现循环强引用,无法销毁实例回收内存

==》通过定义类之间的关系为弱引用weak或无主引用unowned,以替代强引用,从而解决循环强引用的问题,弱引用和无主引用允许循环引用中的一个实例引用另外一个实例而不保持强引用。这样实例能够互相引用而不产生循环强引用

a.对于生命周期中会变为nil的实例使用弱引用,它不会阻止 ARC 销毁被引用的实例,声明属性或者变量时,在前面加上weak关键字表明这是一个弱引用,因为弱引用可以没有值,你必须将每一个弱引用声明为可选类型,ARC 会在引用的实例被销毁后自动将可选的变量赋值为nil

b.对于初始化赋值后再也不会被赋值为nil的实例,使用无主引用,无主引用总是被定义为非可选类型(non-optional type)。你可以在声明属性或者变量时,在前面加上关键字unowned表示这是一个无主引用。

c.两个属性都必须有值,并且初始化完成后永远不会为nil时,需要一个类使用无主引用,而另外一个类使用隐式解析可选属性(解包"!",可直接访问该属性)

2.闭包引起的循环强引用:循环强引用还会发生在当你将一个闭包赋值给类实例的某个属性,并且这个闭包体中又使用了这个类实例时(闭包“捕获”类实例的self)

a.在定义闭包时同时定义捕获列表作为闭包的一部分,通过这种方式可以解决闭包和类实例之间的循环强引用,捕获列表定义了闭包体内捕获一个或者多个引用类型的规则。跟解决两个类实例间的循环强引用一样,声明每个捕获的引用为弱引用或无主引用,而不是强引用。应当根据代码关系来决定使用弱引用还是无主引用。

b.捕获列表中的每一项都由一对元素组成,一个元素是weak或unowned关键字,另一个元素是类实例的引用(例如self)或初始化过的变量(如delegate = self.delegate!)。这些项在方括号中用逗号分开。

c.在闭包和捕获的实例总是互相引用并且总是同时销毁时,将闭包内的捕获定义为无主引用。相反的,在被捕获的引用可能会变为nil时,将闭包内的捕获定义为弱引用。弱引用总是可选类型,并且当引用的实例被销毁后,弱引用的值会自动置为nil。这使我们可以在闭包体内检查它们是否存在

*/

class Person {

let name: String

init(name: String) {

self.name = name

print("\(name) is being initialized")

}

deinit {

print("\(name) is being deinitialized")

}

}

var reference1: Person?     //这里只是定义了变量为可选的Person类型,并未创建引用到类Person的实例

var reference2: Person?

var reference3: Person?

reference1 = Person(name: "John Appleseed")     //创建引用

// prints "John Appleseed is being initialized”

reference2 = reference1                         //都引用的同一个实例

reference3 = reference1

reference1 = nil

reference2 = nil

reference3 = nil                                //只有当最后一个对实例的引用被断开时,ARC才会触发析构方法,销毁实例,而回收内存

// 打印 “John Appleseed is being deinitialized”

//============类实例之间的互相引用,均为可选类型,弱引用========

class Person1 {

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: Person1?

deinit { print("Apartment \(unit) is being deinitialized") }

}

var john: Person1?

var unit4A: Apartment?

john = Person1(name: "John Appleseed")

//对Person1实例的引用有2个:john(强引用)和unit4A!.tenant(弱引用),只要切断john的强引用,该实例就会被销毁,同时销毁其属性john!.apartment对其他实例的强引用,

unit4A = Apartment(unit: "4A")

john!.apartment = unit4A

unit4A!.tenant = john

john = nil

// 打印 “John Appleseed is being deinitialized”

unit4A = nil                        //由于再也没有指向Apartment实例的强引用,该实例会被销毁

// 打印 “Apartment 4A is being deinitialized”

//==============一个可选类型,一个必须有值,则无主引用==========

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 john1: Customer?

john1 = Customer(name: "John Appleseed")

john1!.card = CreditCard(number: 1234_5678_9012_3456, customer: john1!)

john1 = nil

//由于Customer实例的强引用只有john1,切断john1的强引用,则Customer实例被销毁,而对CreditCard实例的强引用只有john1!.card,则CreditCard实例也同时被销毁

// 打印 “John Appleseed is being deinitialized”

// 打印 ”Card #1234567890123456 is being deinitialized”

//===============两个类都必须有值,分别用无主引用、隐式解析可选属性=======

class Country {

let name: String

var capitalCity: City!      //capitalCity声明为隐式解析可选类型的属性,默认值为nil,但是不需要展开它的值就能直接访问它。

init(name: String, capitalName: String) {

self.name = name

self.capitalCity = City(name: capitalName, country: self)   //由于capitalCity默认值为nil,一旦Country的实例在构造函数中给name属性赋值后,整个初始化过程就完成了。这意味着一旦name属性被赋值后,Country的构造函数就能引用并传递隐式的self。Country的构造函数在赋值capitalCity时,就能将self作为参数传递给City的构造函数。

}

}

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”

//=============类和闭包之间的相互引用=======

class HTMLElement {

let name: String

let text: String?

lazy var asHTML: Void -> String = {

[unowned self] in                   //在闭包中使用了对本类实例的无主引用self

if let text = self.text {

return "<\(self.name)>\(text)</\(self.name)>"

} 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())

// 打印 “<p>hello, world</p>”

paragraph = nil

// 打印 “p is being deinitialized”

swift学习笔记之-自动引用计数的更多相关文章

  1. swift学习笔记5——其它部分(自动引用计数、错误处理、泛型...)

    之前学习swift时的个人笔记,根据github:the-swift-programming-language-in-chinese学习.总结,将重要的内容提取,加以理解后整理为学习笔记,方便以后查询 ...

  2. swift 学习之自动引用计数

    swift 学习之自动引用计数 学习和研究的主要是"实例对象和实例对象直接的相会强引用所产生的内从泄漏"和"使用闭包产生的强引用造成的内存泄漏" 注意:只有以引 ...

  3. swift 学习- 18 -- 自动引用计数

    // Swift 使用 自动引用计数 (ARC) 机制来跟踪和管理你的应用程序的内存, 通常情况下, Swift 内存管理机制会一直起作用, 你无须自己来考虑内存的管理, ARC 会在类的实例不再被使 ...

  4. swift:自动引用计数ARC

    Swift自动引用计数:ARC    原文链接:https://numbbbbb.gitbooks.io/-the-swift-programming-language-/content/chapte ...

  5. Swift 学习笔记 (三) 之循环引用浅析

    原创:转载请注明出处 110.自动引用计数实践 下面的例子展示了自动引用计数的工作机制.例子以一个简单的Person类开始,并定义了一个叫name的常量属性: class Person {     l ...

  6. Swift基础语法-内存管理, 自动引用计数

    1. 工作机制 Swift和OC一样,采用自动引用计数来管理内存 当有一个强引用指向某一个对象时,该对象的引用计数会自动+1 当该强引用消失时,引用计数会自动-1 当引用计数为0时,该对象会被销毁 2 ...

  7. swift详解之九---------------自动引用计数、循环引用

    自动引用计数.循环引用(这个必须理解,必须看) 注:本文详细介绍自动引用计数,以及各种循环引用问题.一网打尽! 1. 自动引用计数原理 Swift 使用ARC机制来跟踪和管理你的内存,一般情况下,Sw ...

  8. Swift 自动引用计数(ARC)

    Swift 使用自动引用计数(ARC)这一机制来跟踪和管理应用程序的内存 通常情况下我们不需要去手动释放内存,因为 ARC 会在类的实例不再被使用时,自动释放其占用的内存. 但在有些时候我们还是需要在 ...

  9. Swift ARC 自动引用计数

    1.ARC 引用类型在堆上的内存分配过程中有 8 字节的地址长度用来保存对象的引用计数,堆上的内存并不像栈上那样立即进行回收,系统会定时对堆上的内存进行检查,当某个实例不再被使用时,引用计数会变为 0 ...

随机推荐

  1. 实现快速迭代的引擎设计 - Capcom RE Engine的架构与实现

    [译]实现快速迭代的引擎设计 - Capcom RE Engine的架构与实现 ken hu· 6 天前 原文(日文):ラピッドイテレーションを実現するゲームエンジンの設計 CEDEC2016上的一个 ...

  2. ORA-12170:TNS:连接超时

    本文转自 http://www.cnblogs.com/kerrycode/archive/2012/12/14/2818421.html 1:首先检查网络是否能ping通 2:检查TNS配置(TNS ...

  3. HandlerMethodArgumentResolver数据绑定无效

    因项目中action参数过多,并且是一些通用的查询参数,所以准备进行对参数统一封装为Map对象,然后由action中传入service中进行处理,查询spring的资料发现可以通过实现HandlerM ...

  4. 各种Camera,总有一款适合你(一)

    根据游戏类型的不一样,会需要各种各样的摄像机,下面将分享三种典型的摄像机类型:(1)地下城摄像机:(2)第三人称跟随摄像机:(3)鼠标控制旋转摄像机.将这些控制脚本拖动到场景的MainCamera上即 ...

  5. 爬虫技术 -- 进阶学习(九)使用HtmlAgilityPack获取页面链接(附c#代码及插件下载)

    菜鸟HtmlAgilityPack初体验...弱弱的代码... Html Agility Pack是一个开源项目,为网页提供了标准的DOM API和XPath导航.使用WebBrowser和HttpW ...

  6. [Python] Search navigation in Pycharm

    From: http://blog.csdn.net/u013088062/article/details/50323393 From: http://blog.csdn.net/u013088062 ...

  7. jqmobile小技巧

    jqmobile API好像是不全,很多查不到.记录下自己的发现: 1.popup:data-position-to能够指向class或者id:data-position-to="#id|| ...

  8. ShortcutMapper – 热门应用程序的可视化快捷键

    ShortcutMapper 是一个流行应用程序的键盘快捷键映射.该应用程序使用 Ajax 调用来加载键盘和应用程序数据.首先,试图找到一个在线资源,其中列出了每个平台的所有应用程序快捷方式.然后你可 ...

  9. Spring基础——在 IOC 容器中 Bean 之间的关系

    一.在 Spring IOC 容器中 Bean 之间存在继承和依赖关系. 需要注意的是,这个继承和依赖指的是 bean 的配置之间的关系,而不是指实际意义上类与类之间的继承与依赖,它们不是一个概念. ...

  10. 【UWP】对 Thickness 类型属性进行动画

    好几个月没写 blog 了,一个是在忙新版的碧影壁纸,另一方面是等(观望)周年更新的 api(不过现在还是比较失望,仍然没法支持矩形以外的 Clip).闲话少说,进入主题. 在 UWP 中,出于性能考 ...