Swift学习之内存管理
2020-01-13 本文已影响0人
coderhlt
一、引用管理
和OC一样,Swift也是采取基于引用计数的ARC内存管理
var s:Student? = Student()
weak var s1:Student? = Student()
- 强引用:默认情况下都是强引用
- 弱引用:通过关键字weak修饰
class Student {
var age:Int = 0
}
unowned var s2:Student? = Student()
print(s2?.age)
- 无主引用: 通过unowned修饰。不会产生强引用,实例销毁后仍然存储着实例的内存地址。试图在实例销毁后访问无主引用,会产生运行时错误。
Fatal error: Attempted to read an unowned reference but object 0x100600660 was already deallocated
二、循环引用
2.1
class Student {
var p0:Person?
deinit {
print("销毁 ")
}
}
class Person {
var s0:Student?
deinit {
print("销毁 ")
}
}
var s:Student? = Student()
var p:Person? = Person()
s?.p0 = p
p?.s0 = s
p = nil
s = nil
Person和Student都不会销毁,虽然指向Person对象的p强指针和指向Student对象的s强指针不再引用对象了,但是Person对象的属性s0指针强引用着Student对象,Student对象的属性
p0指针强引用着Person对象,这样就产生了相互引用
class Student {
weak var p0:Person?
deinit {
print("销毁 ")
}
}
想要打破相互引用的局面,对属性指针置弱就可以了。p0 用weak修饰,也就意味着p = nil ,Person对象没有被任何强指针引用,就会销毁,自然Student对象也就销毁了。
2.2、闭包的循环引用
class Person {
var fn:(() -> ())? //闭包作为存储属性,声明格式:(函数类型)?
var fn1:((Int) ->(Int))?
func run() {
print("run")
}
deinit {
print("deinit")
}
}
func test (){
let p = Person()
p.fn = {
p.run()
}
}
test()
- 闭包表达式默认会对用的外层对象产生额外的强引用(对外层对象进行了retain操作),导致对象p无法销毁。
p.fn = {
[weak p] in
p?.run()
}
p.fn = {
[unowned p] in
p.run()
}
- 在闭包表达式的捕获列表声明weak或unowed引用,解决循环引用问题。
- weak、unowned都能解决循环引用的问题,unowned要比weak少一些性能消耗。
- 在生命周期中可能会变为nil的使用weak
- 初始化赋值后再也不会变为nil的使用unowned
class Person{
lazy var fn:(() -> ()) = {[weak self] in self?.run()}
func run(){print(“run”)}
deinit{print(“deinit")}
- 左边的闭包fn内部如果用到了实例成员(属性、方法)
- 编译器会强制要求明确写出self
class Person{
var age: Int = 0
lazy var getAge:Int = {
self.age
}()
如果lazy属性是闭包调用的结果,那么不用考虑循环引用的问题(因为闭包调用后,闭包的生命周期就结束了 )