1、每创建一个类的实例对象,ARC就会分配一块内存来存储实例信息(实例的类型信息及实例的存储属性) 2、当实例不再被使用时,ARC 释放实例所占用的内存,这确保了不再被使用的实例,不会一直占用内存空间 3、当 ARC 释放了正在被使用中的实例,该实例的属性和方法将不能再被访问和调用。实际上,如果你试图访问这个实例,你的应用程序很可能会崩溃 4、为了确保使用中的实例不会被销毁,ARC 会跟踪和计算每一个实例正在被多少属性,常量和变量所引用。哪怕实例的引用数为1,ARC都不会销毁这个实例
class Student{
let name:String
init(name:String) {
self.name = name
print("init")
}
deinit {
print("deinit")
}
}
var stu0:Student? //nil
var stu1:Student? //nil
var stu2:Student? //nil
stu0 = Student.init(name: "lilei") //打印log:init
stu1 = stu0
stu2 = stu0
stu0 = nil
stu1 = nil
stu2 = nil //打印log:deinit
循环引用
class ClassA{
let aStr:String
var b:ClassB?
init(str:String) {
self.aStr = str
}
deinit {
print("ClassA释放")
}
}
class ClassB{
let bStr:String
var a:ClassA?
init(str:String) {
self.bStr = str
}
deinit {
print("ClassB释放")
}
}
var objA:ClassA?
var objB:ClassB?
objA = ClassA(str: "A")
objB = ClassB(str: "B")
objA!.b = objB
objB!.a = objA
objA = nil
objB = nil
weak
关键字表明这是一个弱引用Snip20190523_7.png
class ClassA{
let aStr:String
var b:ClassB?
init(str:String) {
self.aStr = str
}
deinit {
print("ClassA释放") //正常打印
}
}
class ClassB{
let bStr:String
weak var a:ClassA?
init(str:String) {
self.bStr = str
}
deinit {
print("ClassB释放") //正常打印
}
}
var objA:ClassA?
var objB:ClassB?
objA = ClassA(str: "A")
objB = ClassB(str: "B")
objA!.b = objB
objB!.a = objA
objA = nil
objB = nil
unowned
表示这是一个无主引用Snip20190523_8.png
class ClassA{
let aStr:String
var b:ClassB?
init(str:String) {
self.aStr = str
}
deinit {
print("ClassA释放") //正常打印
}
}
class ClassB{
let bStr:String
unowned var a:ClassA?
init(str:String) {
self.bStr = str
}
deinit {
print("ClassB释放") //正常打印
}
}
var objA:ClassA?
objA = ClassA(str: "A")
objA!.b = ClassB(str: "B")
objA = nil //当objA释放后,那么ClassB也被释放
将一个闭包赋值给类实例的某个属性,并且这个闭包体中又使用了这个类实例时。这个闭包体中可能访问了实例的某个属性,例如self.someProperty,或者闭包中调用了实例的某个方法,例如self.someMethod()。这两种情况都导致了闭包“捕获”self,从而产生了循环强引用
闭包引起的循环强引用
class ClassA{
let strA: String
let showValue:Bool
//定义了一个lazy属性closures,这个属性引用了strA的闭包,该属性是Void -> String类型
//默认情况下,闭包赋值给了closures属性,这个闭包返回一个字符串
lazy var closures: () -> String = {
if self.showValue {
return self.strA
} else {
return "空空如也"
}
}
init(str:String, show:Bool) {
self.strA = str
self.showValue = show
}
deinit {
print("A释放")
}
}
var objA:ClassA?
objA = ClassA.init(str: "AA",show: true)
var log:String = objA!.closures()
print(log)
objA = nil
//打印:A释放
在定义闭包的时候,再定义捕获列表作为闭包的一部分,捕获列表定义了闭包体内捕获一个或者多个引用类型的规则。跟解决两个类实例间的循环强引用一样,声明每个捕获的引用为弱引用或无主引用
定义捕获列表
捕获列表中的每一项都由一对元素组成,一个元素是weak
或unowned
关键字,另一个元素是类实例的引用(例如self
)或初始化过的变量(如delegate = self.delegate!
),这些项在方括号中用逗号分开
lazy var someClosure: (Int, String) -> String = {
[unowned self, weak delegate = self.delegate!] (index: Int, stringToProcess: String) -> String in
// 这里是闭包的函数体
}
lazy var someClosure: Void -> String = {
[unowned self, weak delegate = self.delegate!] in
// 这里是闭包的函数体
}
弱引用:在被捕获的引用可能会变为nil时,将闭包内的捕获定义为弱引用
无主引用 :在闭包和捕获的实例总是互相引用并且总是同时销毁时,将闭包内的捕获定义为无主引用
如果被捕获的引用绝对不会变为nil,应该用无主引用,而不是弱引用
解决闭包引起的循环强引用
class ClassA{
let strA: String
let showValue:Bool
//定义了一个lazy属性closures,这个属性引用了strA的闭包,该属性是Void -> String类型
//默认情况下,闭包赋值给了closures属性,这个闭包返回一个字符串
lazy var closures: () -> String = {
//捕获列表是[unowned self],表示“将self捕获为无主引用而不是强引用”
[unowned self] in
if self.showValue {
return self.strA
} else {
return "空空如也"
}
}
init(str:String, show:Bool) {
self.strA = str
self.showValue = show
}
deinit {
print("A释放")
}
}
var objA:ClassA?
objA = ClassA.init(str: "AA",show: true)
var log:String = objA!.closures()
print(log)
objA = nil
打印:
AA
A释放