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

参考练习代码:

 import Foundation

 // Swift使用自动引用计数(ARC)机制来跟踪和管理你的应用程序的内存。
// 引用计数仅仅应用于类的实例。结构体和枚举类型是值类型,不是引用类型,也不是通过引用的方式存储和传递。 // ----------------- Part 1 -------------------------
// 下面的例子展示了自动引用计数的工作机制。
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?
var reference2: Person?
var reference3: Person? reference1 = Person(name: "John Appleseed")
// reference1到Person类的新实例之间建立了一个强引用
// 正是因为这一个强引用,ARC 会保证 Person 实例被保持在内存中不被销毁 reference2 = reference1
reference3 = reference2
// 现在这一个Person实例已经有三个强引用了 reference1 = nil
reference3 = nil
// 给其中两个变量赋值 nil 的方式断开两个强引用(包括最先的那个强引用),只留下一个强引用, Person实例不会被销毁 reference2 = nil
// 最后一个强引用被断开,Person实例被销毁 // ----------------- Part 2 -----------------
// 循环强引用问题,一个类实例的强引用数永远不能变成0
class Person {
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 }
var tenant: Person?
deinit { print("Apartment \(unit) is being deinitialized") }
}
var john: Person?
var unit4A: Apartment? john = Person(name: "John Appleseed")
unit4A = Apartment(unit: "4A")
// 变量john现在有一个指向Person实例的强引用,而变量unit4A有一个指向Apartment实例的强引用 john!.apartment = unit4A
unit4A!.tenant = john
// 这两个实例关联后会产生一个循环强引用 john = nil
unit4A = nil
// 当你断开john和unit4A引用时,引用计数并不会减为0,实例也不会被ARC销毁 // ----------------- Part 3 -----------------
// Swift提供了两种办法用来解决你在使用类的属性时所遇到的循环强引用问题:弱引用(weak reference)和无主引用(unowned reference)。
class Person {
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: Person?
deinit { print("Apartment \(unit) is being deinitialized") }
} // 跟之前一样,建立两个变量( john 和 unit4A )之间的强引用,并关联两个实例
var john: Person?
var unit4A: Apartment?
john = Person(name: "John Appleseed")
unit4A = Apartment(unit: "4A")
john!.apartment = unit4A
unit4A!.tenant = john
// Person实例依然保持对Apartment实例的强引用,但是Apartment实例只是对Person实例的弱引用。
// 这意味着当你断开john变量所保持的强引用时,再也没有指向Person实例的强引用了 john = nil
// 唯一剩下的指向Apartment实例的强引用来自于变量unit4A。如果你断开这个强引用,再也没有指向Apartment实例的强引用了
unit4A = nil
// 首先断开unit4A的对Apartment实例的强引用,并不会使得Apartment实例销毁,因为此时Person实例依旧有对Apartment实例的强引用 // ----------------- Part 4 -----------------
// 下面的例子定义了两个类, Customer 和 CreditCard ,模拟了银行客户和客户的信用卡。
// 这两个类中,每一个都将另外一个类的实例作为自身的属性。这种关系可能会造成循环强引用。
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 john: Customer?
john = Customer(name: "John Appleseed")
john!.card = CreditCard(number: 1234_5678_9012_3456, customer: john!)
// Customer 实例持有对 CreditCard 实例的强引用,而 CreditCard 实例持有对 Customer 实例的无主引用。 john = nil // ----------------- Part 4 -----------------
//Person和Apartment的例子展示了两个属性的值都允许为nil,并会潜在的产生循环强引用。这种场景最适合用弱引用来解决。
//Customer和CreditCard的例子展示了一个属性的值允许为nil,而另一个属性的值不允许为nil,这也可能会产生循环强引用。这种场景最适合通过无主引用来解决。
//存在着第三种场景,在这种场景中,两个属性都必须有值,并且初始化完成后永远不会为nil。在这种场景中,需要一个类使用无主属性,而另外一个类使用隐式解析可选属性。
class Country {
let name: String
var capitalCity: City!
init(name: String, capitalName: String) {
self.name = name
self.capitalCity = City(name: capitalName, country: self)
}
deinit { print("Country \(name) is being deinitialized") }
}
class City {
let name: String
unowned let country: Country
init(name: String, country: Country) {
self.name = name
self.country = country
}
deinit { print("City \(name) is being deinitialized") }
}
var country = Country(name: "Canada", capitalName: "Ottawa")
print("\(country.name)'s capital city is called \(country.capitalCity.name)")
// 以上的意义在于你可以通过一条语句同时创建Country和City 的实例,而不产生循环强引用,并且capitalCity的属性能被直接访问,而不需要通过感叹号来展开它的可选值
country = Country(name: "China", capitalName: "Beijing") // ----------------- Part 5 -----------------
// 循环强引用还会发生在当你将一个闭包赋值给类实例的某个属性,并且这个闭包体中又使用了这个类实例。
// 这个闭包体中可能访问了实例的某个属性,例如self.someProperty,或者闭包中调用了实例的某个方法,例如 self.someMethod 。
// 这两种情况都导致了闭包 “捕获" self ,从而产生了循环强引用。
// 循环强引用的产生,是因为闭包和类相似,都是引用类型
class HTMLElement {
let name: String
let text: String?
lazy var asHTML: Void -> String = {
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 heading = HTMLElement(name: "h1")
let defaultText = "some default text"
heading.asHTML = {
return "<\(heading.name)>\(heading.text ?? defaultText)</\(heading.name)>"
}
print(heading.asHTML())
heading = HTMLElement(name: "head") // HTMLElement类产生了类实例和asHTML默认值的闭包之间的循环强引用。
var paragraph: HTMLElement? = HTMLElement(name: "p", text: "hello, world")
print(paragraph!.asHTML())
paragraph = nil // ----------------- Part 6 -----------------
// Swift提供了一种优雅的方法来解决这个问题,称之为闭包捕获列表(closuer capture list)
// 在定义闭包时同时定义捕获列表作为闭包的一部分,捕获列表定义了闭包体内捕获一个或者多个引用类型的规则
// Swift有如下要求:只要在闭包内使用self的成员,就要用self.someProperty(而非someProperty)。这提醒你可能会一不小心就捕获了self。
// 捕获列表中的每一项都由一对元素组成,一个元素是unowned或weak关键字。
// 另一个元素是类实例的引用(如self)或初始化过的变量(如self.someProperty)
class HTMLElement {
let name: String
let text: String?
lazy var asHTML: Void -> String = {
[unowned self] in
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())
paragraph = nil

Swift学习笔记-ARC的更多相关文章

  1. 【swift学习笔记】二.页面转跳数据回传

    上一篇我们介绍了页面转跳:[swift学习笔记]一.页面转跳的条件判断和传值 这一篇说一下如何把数据回传回父页面,如下图所示,这个例子很简单,只是把传过去的数据加上了"回传"两个字 ...

  2. Swift学习笔记(一)搭配环境以及代码运行成功

    原文:Swift学习笔记(一)搭配环境以及代码运行成功 1.Swift是啥? 百度去!度娘告诉你它是苹果最新推出的编程语言,比c,c++,objc要高效简单.能够开发ios,mac相关的app哦!是苹 ...

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

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

  4. swift学习笔记4——扩展、协议

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

  5. swift学习笔记3——类、结构体、枚举

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

  6. swift学习笔记2——函数、闭包

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

  7. swift学习笔记1——基础部分

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

  8. Swift学习笔记一

    最近计划把Swift语言系统学习一下,然后将MagViewer用这种新语言重构一次,并且优化一下,这里记录一下Swift的学习笔记. Swift和Objective-C相比,在语法和书写形式上做了很多 ...

  9. 记录:swift学习笔记1-2

    swift还在不断的更新做细微的调整,都说早起的鸟儿有虫吃,那么我们早点出发吧,趁着国内绝大多数的coder们还没有开始大范围普遍应用. 网上有些大神说:swift很简单!我不同意这个观点,假如你用h ...

  10. Swift学习笔记(14)--方法

    1.分类 方法分为实例方法和类型方法 实例方法(Instance Methods):与java中的类似,略 类型方法(Type Methods):与java.oc中的类方法类似.声明类的类型方法,在方 ...

随机推荐

  1. atitit.农历的公式与原理以及农历日期运算

    atitit.农历的公式与原理以及农历日期运算 1. 农历的概述1 2. 如何在电脑程序里面计算农历??1 3. 农历的公式2 4. 获取当日农历日历3 5. 历史日期公式加查表才能得到精确日期3 6 ...

  2. 如何将github上的 lib fork之后通过podfile 改变更新源到自己fork的地址

    解决办法: http://stackoverflow.com/questions/20936885/cocoapods-and-github-forks 就是fork完后,提交更改到自己的github ...

  3. PL/SQL重新编译包无反应

    前几天碰到一个有趣的事情:早上同事执行一个包很久没有反应,就中断了执行,发邮件让我帮忙查看具体情况,我用PL/SQL Developer登录后,找到这个包的过程中发现这个包的图标有红色叉叉,也就是说这 ...

  4. MySQL初始化的正确姿势

    1. 背景 mysql安装教程很多,但是有不少讲得过于简单,没有考虑到安全问题.比如说,一些教程里,只设置一个root用户,并且对外网公开,一来容易被破解密码(用户名固定,破解难度自然降了一大截,而且 ...

  5. Solr图形化界面banana:除Hue之外的选择

    最近Hue+Solr 方案原型验证有了一些进展.正好也收到了Google的大数据专家Sam的来件询问进展,我答复如下: Sam, 你好. 已经把Kafka+flume+solr的实时索引搭建起来了, ...

  6. Java多线程-并发容器

    Java多线程-并发容器 在Java1.5之后,通过几个并发容器类来改进同步容器类,同步容器类是通过将容器的状态串行访问,从而实现它们的线程安全的,这样做会消弱了并发性,当多个线程并发的竞争容器锁的时 ...

  7. Memcached学习笔记

    [TOC] 前言 此为学习笔记汇总,如有纰漏之处,还望不吝指出,谢谢. 启动流程 调用settings_init()设定初始化参数 从启动命令中读取参数来设置setting值 设定LIMIT参数 开始 ...

  8. Hibernate注解----关联映射注解以及课程总结详解----图片版本

    上一篇,记录了Hibernate注解----类级别注解以及属性注解详解 ,我们这一节主要讲解的是Hibernate注解----关联映射注解以及课程总结详解. 本节的主要内容: 第3章 关联映射注解 3 ...

  9. Shelve Instance 操作详解 - 每天5分钟玩转 OpenStack(38)

    Instance 被 Suspend 后虽然处于 Shut Down 状态,但 Hypervisor 依然在宿主机上为其预留了资源,以便在以后能够成功 Resume. 如果希望释放这些预留资源,可以使 ...

  10. Excellent Articles

    Lisp The roots of lisp Recursive Functions of Symbolic Expressions and Their Computation by Machine, ...