Swift 内存管理简介6

109 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第20天,点击查看活动详情

本质是用64位的指针,把当前的side存储到64位位域中,并设置一些标记位。

Side Table 是⼀种类名为 HeapObjectSideTableEntry 的结构,⾥⾯也有 RefCounts 成员,内部是 SideTableRefCountBits,其实就是原来的 uint64_t 加上⼀个存储弱引⽤数的 uint32_t

image.png

2.2 Unowned

和弱引⽤类似,⽆主引⽤不会牢牢保持住引⽤的实例。但是不像弱引⽤,总之,⽆主引⽤假定是永远有值。

class ZGTeacher {
    var age: Int = 18
    var name: String = "zhang"
}

var t: ZGTeacher?
t = ZGTeacher()

print(Unmanaged.passUnretained(t as AnyObject).toOpaque())

unowned var t1 = t

t = nil

print(t1)

这里产生了崩溃,因为unowned修饰的t1必须是假定有值的,t或者t1为nil就产生了崩溃。
当我们知道两个对象的⽣命周期并不相关,那么我们必须使⽤ weak。相反,⾮强引⽤对象拥有和强引⽤对象同样或者更⻓的⽣命周期的话,则应该使⽤ unowned
我们来看一下这个例子:

class ZGTeacher {
    var age: Int = 18
    var name: String = "zhang"
    var subject: ZGSubject?
}

class ZGSubject {
    var subjectName: String
    var subjectTeacher: ZGTeacher
    init(_ subjectName: String, _ subjectTeacher: ZGTeacher) {
        self.subjectName = subjectName
        self.subjectTeacher = subjectTeacher
    }
}

var t = ZGTeacher()

var subject = ZGSubject.init("swift", t)

t.subject = subject

这个过程中我们的Teacher和SubjectName,如果老师不在了,那么这个过程中所讲授的课程也就不在了。
这个过程中我们可以通过unowned来解决这个循环引用,也就意味着当前的生命周期ZGTeacher更长。

class ZGTeacher {
    var age: Int = 18
    var name: String = "zhang"
    var subject: ZGSubject?
}

class ZGSubject {
    var subjectName: String
    ///这里添加 unowned
    unowned  var subjectTeacher: ZGTeacher
    init(_ subjectName: String, _ subjectTeacher: ZGTeacher) {
        self.subjectName = subjectName
        self.subjectTeacher = subjectTeacher
    }
}

var t = ZGTeacher()

var subject = ZGSubject.init("swift", t)

t.subject = subject

2.3 Weak VS Unowned比较

注意weak相对于unowned更安全,但是unowned相对于weak性能更好。因为weak需要重新创建一个sideTable散列表,还要对我们当前的sideTable散列表进行操作,而unowned直接操作了我们64的信息,但是在使用过程中要确保unowned是有值的。

2.4 闭包循环引用

var age = 18
let closure = {
    age += 1
}

closure()
print(age)

lldb输出打印结果

19

我们的闭包会⼀般默认捕获我们外部的变量,闭包内部对变量的修改将会改变外部原始变量的值
下面的案例就是闭包循环引用的经典案例,对象无法释放。

class ZGTeacher {
    var age: Int = 18
    var name: String = "zhang"
    var testClosure: (() -> ())?
    deinit {
        print("ZGTeacher deinit")
    }
}

func test() {
    let t = ZGTeacher()
    t.testClosure = {
        t.age += 1
    }
    
    print("end")
}

test()

那么我们如何解决这一问题哪?可以使用我们当前的捕获列表。

class ZGTeacher {
    var age: Int = 18
    var name: String = "zhang"
    var testClosure: (() -> ())?
    deinit {
        print("ZGTeacher deinit")
    }
}

func test() {
    let t = ZGTeacher()
    t.testClosure = { [weak t] in
        t!.age += 1
    }
    
    print("end")
}

test()