//自动引用计数

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. UNIX环境高级编程笔记之进程环境

    本章讲的都是一些非常基础的知识,目的是为了下一章讲进程控制做铺垫,所以,本章就不做过多的总结了,直接看图吧.

  2. Oracle数据库入门——常用的数据字典

    一.oracle数据字典主要由以下几种视图构成:1.user视图以user_为前缀,用来记录用户对象的信息 2.all视图以all_为前缀,用来记录用户对象的信息及被授权访问的对象信息 3.dba视图 ...

  3. Android之线程回掉更新ui

    一:工作线程中的回掉更新UI public class MainActivity extends AppCompatActivity { private int i; private Callback ...

  4. JavaScript - javascript 中的 "||" 与 "&&" 的理解与灵活运

    你肯定见到过这样的代码:a = a||"xxx". 它其实就等价于下面三种形式的代码: a = a || "xxx"; 与: if (!a) { a = &qu ...

  5. Offer_answer_with_SDP_rfc3264

    Network Working Group J. RosenbergRequest for Comments: 3264 dynamicsoftObsoletes: 2543 H. Schulzrin ...

  6. APP-BOM-20516 错误处理一例

    昨天在处理一个工单异常时,需要将一个Released的工单改为Unreleased状态,程序报APP-BOM-20516错误,如下图.百度只搜到两条记录,均无用.Google能搜到的多一些,也无用.进 ...

  7. 使用hessian+protocol buffer+easyUI综合案例--登陆

    首先先简单介绍下hessian ,protocol buffer, easyUI框架 hessian: Hessian是一个轻量级的remoting on http工具,采用的是Binary RPC协 ...

  8. 搭建WebRtc环境

    0.前言 这次的需求,准备做的是一个类似与QQ视频一样的点对点视频聊天.这几天了解了一些知识后,决定使用HTML5新支持的WebRtc来作为视频通讯.客户端使用支持HTML5浏览器即可.服务器段需要提 ...

  9. aliyun ubuntu mysql

    http://www.codingyun.com/article/38.html ------------ python install mysql module ubuntu下mysql-pytho ...

  10. JS思维之路菜鸟也能有大能量(1)--模拟push

    因为本系列文章属于思维类,所以不做基础方法的讲解. 任务:首先我定义了一个变量var arr = [0,1,2,3,4,5];我现在想模拟push方法在这个数组的5后面加东西,我们应该怎么做?给你5分 ...