objective-c强弱引用的思考|青训营笔记

130 阅读3分钟

这是我参与「第四届青训营 」笔记创作活动的第5天

对于一个一直使用c和c++的人来说,初次接触objective-c语言会遇到一个逃不开的语法点——指针的强引用(__strong)和弱引用(__weak)。

那么,什么是强引用、弱引用,设置这样两个关键字是为了解决什么问题呢?
首先,从语法属性来讲,强引用是一个持有的关系,在持有者被销毁前被持有者是不能被销毁的;弱引用是一个指向的关系,指向者和被指向者在「销毁」这件事上不存在任何关系。强引用相当于拥有了对象,弱引用相当于享有对象的信息。

而要探讨强弱引用的作用和意义,我们可以先考虑这样一个c++的经典问题——深拷贝与浅拷贝。

graph TD
A --> space
B --> space

我们假设对象A有一个指针指向了一块内存space,对象B是对象A的浅拷贝,因此也有一个指针指向相同的space。对浅拷贝有所了解的人都知道这样的情况是灾难性的——当A或B销毁(也就是delete时),剩下的那个对象(B或A)的指针就成了野指针,指向了一个不知道合不合法的地方。

那么如何解决这样的问题呢?我们都知道深拷贝是一种标准的解决方法,但是深拷贝的代价就是多复制了一份内存空间,在有些时候是不必要的。那么还有别的解决方法吗?

第一种方法是当A或B销毁时,自动让另一方的指针置零,这样就达到了一份空间多重引用的效果,但是这样对于“平级”的关系时并不好用——A销不销毁和B销不销毁无关时。但是这样的做法对于「主次」「父子」的关系却恰到好处。

比如,我们有100份A类的对象指针,有一份可能指向100份中任意一份的A类的“自由指针”,那么这100份指针就可以看作100个“主人”,这个“自由指针”可以看作“来去自如”的“客人”,此时这个自由指针最好就是一个弱引用指针;又比如这样一个几何图形,它有一个三角形、一个矩形、一个圆形构成,它拥有三角类、矩形类、圆类的三个“子指针”。假设三角类、矩形类、圆类和这个三者的组合类都具有“平移”的功能,那么为了获取“父类”(也就是这个组合类)的移动信息,这三个“子类”都必须拥有一个指向“父类”的指针(整体移动部分必须跟着移动),但显然,两者是「父子」「整体与部分」的关系,不是相互持有的关系,因此,组合类拥有三个指向“单类”的强引用指针,三个“单类”拥有一个指向父类的弱引用指针,这样才是合理的指向关系。这种情况在app开发的过程中经常遇到,比如父视图和子视图就是这样的关系。

第二种做法就是进行引用计数,当有n份指针时就记录n个数,销毁一个指针后就减少一个数,直至计数为0,才把被指向的那块内存回收。在我们前面提到的A和B的例子中,也就是当A销毁时,内存space并不销毁(因为此时计数由2变1但不为0),直到B也被销毁时,内存space才被销毁。而这,也是c++智能指针和objective-c内存回收机制的原理(当然也是许多其他语言内存回收机制的最根本原理)。