Swift学习笔记-ARC
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的更多相关文章
- 【swift学习笔记】二.页面转跳数据回传
上一篇我们介绍了页面转跳:[swift学习笔记]一.页面转跳的条件判断和传值 这一篇说一下如何把数据回传回父页面,如下图所示,这个例子很简单,只是把传过去的数据加上了"回传"两个字 ...
- Swift学习笔记(一)搭配环境以及代码运行成功
原文:Swift学习笔记(一)搭配环境以及代码运行成功 1.Swift是啥? 百度去!度娘告诉你它是苹果最新推出的编程语言,比c,c++,objc要高效简单.能够开发ios,mac相关的app哦!是苹 ...
- swift学习笔记5——其它部分(自动引用计数、错误处理、泛型...)
之前学习swift时的个人笔记,根据github:the-swift-programming-language-in-chinese学习.总结,将重要的内容提取,加以理解后整理为学习笔记,方便以后查询 ...
- swift学习笔记4——扩展、协议
之前学习swift时的个人笔记,根据github:the-swift-programming-language-in-chinese学习.总结,将重要的内容提取,加以理解后整理为学习笔记,方便以后查询 ...
- swift学习笔记3——类、结构体、枚举
之前学习swift时的个人笔记,根据github:the-swift-programming-language-in-chinese学习.总结,将重要的内容提取,加以理解后整理为学习笔记,方便以后查询 ...
- swift学习笔记2——函数、闭包
之前学习swift时的个人笔记,根据github:the-swift-programming-language-in-chinese学习.总结,将重要的内容提取,加以理解后整理为学习笔记,方便以后查询 ...
- swift学习笔记1——基础部分
之前学习swift时的个人笔记,根据github:the-swift-programming-language-in-chinese学习.总结,将重要的内容提取,加以理解后整理为学习笔记,方便以后查询 ...
- Swift学习笔记一
最近计划把Swift语言系统学习一下,然后将MagViewer用这种新语言重构一次,并且优化一下,这里记录一下Swift的学习笔记. Swift和Objective-C相比,在语法和书写形式上做了很多 ...
- 记录:swift学习笔记1-2
swift还在不断的更新做细微的调整,都说早起的鸟儿有虫吃,那么我们早点出发吧,趁着国内绝大多数的coder们还没有开始大范围普遍应用. 网上有些大神说:swift很简单!我不同意这个观点,假如你用h ...
- Swift学习笔记(14)--方法
1.分类 方法分为实例方法和类型方法 实例方法(Instance Methods):与java中的类似,略 类型方法(Type Methods):与java.oc中的类方法类似.声明类的类型方法,在方 ...
随机推荐
- ArcGIS JS 学习笔记4 实现地图联动
1.开篇 守望屁股实在太好玩了,所以最近有点懒,这次就先写个简单的来凑一下数.这次我的模仿目标是天地图的地图联动. 天地的地图联动不仅地图有联动,而且鼠标也有联动,我就照着这个目标进行山寨. 2.准备 ...
- Android数据存储方式--SharedPreferences
Android数据存储方式有如下四种:SharedPreferences.存储到文件.SQLite数据库.内容提供者(Content provider).存储到网络服务器. 本文主要介绍一下Share ...
- OC 单例模式
OC 单例模式 概念 单例模式是一种常用的软件设计模式.在它的核心结构中只包含一个被称为单例的特殊类.通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并节约 ...
- Xcode 创建.a和framework静态库(转载)
库介绍 库从本质上来说是一种可执行代码的二进制格式,可以被载入内存中执行.库分静态库和动态库两种. iOS中的静态库有 .a 和 .framework两种形式:动态库有.dylib 和 .framew ...
- 敏捷遇上UML——软创基地马年大会(深圳站 2014-3-15)
邀请函: 尊敬的阁下: 我们将在深圳为您奉献高端知识大餐,当敏捷遇上UML,会发生怎样的化学作用呢?首席专家张老师将会为您分享需求分析及软件设计方面的最佳实践,帮助您掌握敏捷.UML及两者相结合的实战 ...
- [css]我要用css画幅画(五)
接着之前的[css]我要用css画幅画(四), 这次我给小明和静静增加了对话,用了简单的动画效果. github:https://github.com/bee0060/Css-Paint , 完整代码 ...
- [转]HDFS中JAVA API的使用
HDFS是一个分布式文件系统,既然是文件系统,就可以对其文件进行操作,比如说新建文件.删除文件.读取文件内容等操作.下面记录一下使用JAVA API对HDFS中的文件进行操作的过程. 对分HDFS中的 ...
- MS SQL 统计信息浅析上篇
统计信息概念 统计信息是一些对象,这些对象包含在表或索引视图中一列或多列中的数据分布有关的统计信息.数据库查询优化器使用这些统计信息来估计查询结果中的基数或行数. 通过这些基数估计,查询优化器可以生成 ...
- Failed to create AppDomain 'xxx'. Exception has been Failed to create AppDomain
一服务器上的数据库全部被置于紧急模式(EMERGENCY),在错误日志里面能看到大量下面的错误 Failed to create AppDomain "YourSQLDba.dbo[runt ...
- linux c++编译问题和虚拟机网络通信
1.gcc main.cpp -lstdc++ -o test5 2. service network stop service NetworkManager restart