Swift中的可选链与内存管理(干货系列)
干货之前:补充一下可选链(optional chain)
1 class A { 2 var p: B? 3 4 } 5 6 class B 7 { 8 var p: C? 9 } 10 11 class C { 12 func cm() -> String { 13 print("cm") 14 return "abc" 15 } 16 } 17 18 let insa = A() 19 let insb = B() 20 let insc = C() 21 insa.p = insb 22 //insa.p = nil 23 insb.p = insc 24 25 let r = insa.p?.p?.cm()
解析:此处定义了A,B,C三个类,使其依次关联,最后通过类A实例的属性拿到B实例,依次拿到C实例再调用C的方法。
注意:1,中间任何一个地方为nil,不报错,但导致整个结果为nil。
2,如果没有一个地方为nil,整个表达式才正常执行。
内存管理
swift中的或者java,c#语言的内存管理,指的就是引用类型对象的管理,也就是对“堆(heap)”里面的对象的管理。
这三种语言中,值类型不需要进行内存管理,值类型是放在栈里的,程序会自动管理,不需要特别的机制。
swift中的内存管理技术,叫做arc,自动引用计数(Auto Reference Count) 当对对象的引用计数为0时,立即销毁对象
这种管理一般会产生两种错误可能
1.空引用
2.内存泄露(leak) 某个时候,某些对象分配了内存,但因为某些原因,导致程序结束时,此对象所占的内存没有被回收
我们可以控制的引用计数的数量 增加的方法 1.声明变量,指向某个对象(直接new或者把别的变量的值赋值给你 )
减少的方法
1.f = nil(表示不指向任何东西)
2.变量一般会运行在函数中,变量本身是存放在栈中的 所以函数结束时,此变量消失
关于循环引用swift提供了两种方法来解决,
一种是weak(弱),一种是unowned(未拥有)
1.weak 可以修饰在可为空(?,!)的属性上
2.unowned只能修饰在非可为空的属性上。
循环引用案例
1 class A { 2 var p: B? 3 init() { 4 print("a********************") 5 } 6 deinit { 7 print("a--------------------") 8 } 9 } 10 11 class B{ 12 var p: A? 13 init() { 14 print("b********************") 15 } 16 deinit { 17 print("b--------------------") 18 } 19 20 } 21 var f1:A? = A() 22 var f2:B? = B() 23 //使用这两个类时,可以从控制台看到这两个类已经初始化完毕 24 //通过f1f2两个对象的属性将这两个类相互关联 25 f1?.p = f2 26 f2?.p = f1 27 //此时再将这两个对象赋值为nil 28 //f1 = nil 29 //f2 = nil 30 //但此时并没有调用类的析构函数 31 //原因:f1f2这两个对象的属性相互引用了这两个对象 32 f1?.p = nil 33 f2?.p = nil 34 f1 = nil 35 f2 = nil
解析:1,此处现将f1f2两对象的属性赋值为nil再将f1f2赋值为nil即代表A,B这两个类完全没有引用,此时才会调用析构函数,回收内存。
2,以上这种循环引用的问题,对象并没有真正清除常常会导致内存泄漏(leak)
解决方法一:weak
1 class C { 2 var p: D? 3 init() { 4 print("c********************") 5 } 6 deinit { 7 print("c--------------------") 8 } 9 } 10 11 class D{ 12 weak var p: C? 13 init() { 14 print("d********************") 15 } 16 deinit { 17 print("d--------------------") 18 } 19 20 } 21 var f3:C? = C() 22 var f4:D? = D() 23 f3 = nil 24 f4 = nil
此时发现在任何一个循环引用的属性上加上weak关键字,即可解决上述问题
注意:weak 可以修饰在可为空(?,!)的属性上
解决方式二:unowned
1 class E { 2 var p: F? 3 init() { 4 print("e********************") 5 } 6 deinit { 7 print("e--------------------") 8 } 9 } 10 11 class F{ 12 unowned var p: E 13 init(a:E) { 14 p = a 15 print("f********************") 16 } 17 deinit { 18 print("f--------------------") 19 } 20 21 } 22 var f5:E? = E() 23 var f6:F? = F(a:f5!) 24 f5 = nil 25 f6 = nil
注意:unowned只能修饰在非可为空的属性上。