干货之前:补充一下可选链(optional chain)
class A {
var p: B? } class B
{
var p: C?
} class C {
func cm() -> String {
print("cm")
return "abc"
}
} let insa = A()
let insb = B()
let insc = C()
insa.p = insb
//insa.p = nil
insb.p = insc 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只能修饰在非可为空的属性上。
循环引用案例
class A {
var p: B?
init() {
print("a********************")
}
deinit {
print("a--------------------")
}
} class B{
var p: A?
init() {
print("b********************")
}
deinit {
print("b--------------------")
} }
var f1:A? = A()
var f2:B? = B()
//使用这两个类时,可以从控制台看到这两个类已经初始化完毕
//通过f1f2两个对象的属性将这两个类相互关联
f1?.p = f2
f2?.p = f1
//此时再将这两个对象赋值为nil
//f1 = nil
//f2 = nil
//但此时并没有调用类的析构函数
//原因:f1f2这两个对象的属性相互引用了这两个对象
f1?.p = nil
f2?.p = nil
f1 = nil
f2 = nil
解析:1,此处现将f1f2两对象的属性赋值为nil再将f1f2赋值为nil即代表A,B这两个类完全没有引用,此时才会调用析构函数,回收内存。
2,以上这种循环引用的问题,对象并没有真正清除常常会导致内存泄漏(leak)
解决方法一:weak
class C {
var p: D?
init() {
print("c********************")
}
deinit {
print("c--------------------")
}
} class D{
weak var p: C?
init() {
print("d********************")
}
deinit {
print("d--------------------")
} }
var f3:C? = C()
var f4:D? = D()
f3 = nil
f4 = nil
此时发现在任何一个循环引用的属性上加上weak关键字,即可解决上述问题
注意:weak 可以修饰在可为空(?,!)的属性上
解决方式二:unowned
class E {
var p: F?
init() {
print("e********************")
}
deinit {
print("e--------------------")
}
} class F{
unowned var p: E
init(a:E) {
p = a
print("f********************")
}
deinit {
print("f--------------------")
} }
var f5:E? = E()
var f6:F? = F(a:f5!)
f5 = nil
f6 = nil
注意:unowned只能修饰在非可为空的属性上。