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. SharePoint 2013 使用JavaScript对象模型配置智能提示

    前言 默认在VS2012/2013中编写SharePoint JavaScript 客户端对象模型,都没有智能感知的功能,用起来非常麻烦:其实,我们可以手动配置一下,让JavaScript可以进行智能 ...

  2. [转]实现文字跑马灯效果,scrolling text from right to left

    <div> <marquee direction="left" behavior="scroll" scrollamount="10 ...

  3. eclipse启动时报错 Could not create the java virtual machine

    eclipse启动的时候 报错 这是系统为eclipse分配的内存不足,需要去修改  eclipse.ini文件 eclipse.ini是eclipse 内存分配之类的配置文件   对java虚拟机的 ...

  4. iOS 动画绘制线条颜色渐变的折线图

    效果图 .................... 概述 现状 折线图的应用比较广泛,为了增强用户体验,很多应用中都嵌入了折线图.折线图可以更加直观的表示数据的变化.网络上有很多绘制折线图的demo,有 ...

  5. 分享dubbo.xsd和idubbo.xsd的可用地址

    dubbo.xsd和idubbo.xsd的官方地址不可用 http://code.alibabatech.com/schema/dubbo/dubbo.xsd似乎挂了,真是淡淡的忧伤啊,然后就各种报错 ...

  6. WebForm(一)——IIS服务器、开发方式和简单基础

    一.B/S和C/S 1.C/S C/S 架构是一种典型的两层架构,其全程是Client/Server,即客户端服务器端架构,其客户端包含一个或多个在用户的电脑上运行的程序,而服务器端有两种,一种是数据 ...

  7. angularJS 如何读写缓冲

    写在前面 1.在客户端.服务端架构中,HTTP协议是主流通信技术: 2.HTTP协议的无状态特性,节省带宽,较少服务器的负载,缓冲技术具有重要的运用:这里主要讲解在客户端浏览器中angular如何读写 ...

  8. x01.TextProc: 两三分钟完成的一个小工具

    在工作中,遇到这么个问题,需要将 Excel 表中类似 2134-1234-4456 的商品编号输入到单位的程序中,而程序只认 213412344456 这种没有 ‘-’ 的输入.数量比较多,一笔一笔 ...

  9. android 实现点击listview 空白地方隐藏菜单

    思路:重写ListView的setOnTouchListener事件: ListView.setOnTouchListener(new OnTouchListener(){ @Override pub ...

  10. 《InsideUE4》-8-GamePlay架构(七)GameMode和GameState

    我的世界,我做主 引言 上文我们说到在Actor层次,UE用Controller来充当APawn的逻辑控制者,也有了可以接受玩家输入的PlayerController,和能自行行动的AIControl ...