//自动引用计数

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. PHP/MYSQL UTF8 中文排序

    1. 需要在php数组中用中文排序,但是一般使用utf8格式的文件,直接用asort排序不行.用gbk和gb2312可以.这跟几种格式的编码有关系.gbk和gb2312本身的编码就是用拼音排序的. f ...

  2. BATCH(BAT批处理命令语法)

    bat语法备忘扩展名是bat(在nt/2000/xp/2003下也可以是cmd)的文件就是批处理文件[@more@] bat语法备忘扩展名是bat(在nt/2000/xp/2003下也可以是cmd)的 ...

  3. datagrid 动态列

    var options={}; $(function(){ var myNj = 9; //初始化 $("#disgrid").datagrid({ type: 'POST', n ...

  4. eclipse中对项目进行分类管理

    我们在用Eclipse开发的时候通常会建很多类型的项目,如公司项目.自己项目.Demo等等,并且一个项目又可能有一个主项目和多个引用包,如果包所有的项目都放到一个workspace下面,则会引起混来, ...

  5. AssetBundle系列——资源的加载、简易的资源管理器

    每个需要进行资源管理的类都继承自IAssetManager,该类维护它所使用到的所有资源的一个资源列表.并且每个资源管理类可以重写其资源引用接口和解引用接口. 每个管理器有自己的管理策略,比如Scen ...

  6. 【.Net底层剖析】2.stfld指令-给对象的字段赋值

    .Net底层剖析目录章节 1.[深入浅出.Net IL]1.一个For循环引发的IL 2.[.Net底层剖析]2.stfld指令-给对象的字段赋值 3.[.Net底层剖析]3.用IL来理解属性 引言: ...

  7. 使用的 SQL Server 版本不支持数据类型“datetime2”的错误解决方法

    THE VERSION OF SQL IN USE DOES NOT SUPPORT DATATYPE ‘DATETIME2′ 主要错误原因,在使用ado.net entity的时候,entity使用 ...

  8. springboot themleaf 开发笔记

    <form id="form-query" th:action="@{/member-score/rule-save}" th:object=" ...

  9. bower的使用

    一.bower的安装 安装nodejs的最新版本: 安装npm. 由于npm是nodejs的包管理器,所以在将nodejs安装完成后,npm也就自动安装完成. 安装git. 安装bower. 使用 n ...

  10. 使用Html5+C#+微信 开发移动端游戏详细教程:(六)游戏界面布局与性能优化

    本篇教程我们主要讲解在游戏界面上的布局一般遵循哪些原则和一些性能优化的通用方法. 接着教程(五),我们通过Loading类一次性加载了全部图像素材,现在要把我们所用到的素材变成图片对象显示在界面上,由 ...