可能大家都知道如果在block中显式或隐式地引用了self(比如引用了self的成员变量等),则会引发内存泄漏,但又会有人说,如果是类似于NSArray或者Animation的系统block中引用了self不会有问题,这些经验应当都会有一些事实的佐证,但这里面真正的机制是怎样呢?
先了解下cocoa的block本身,在block的诞生之初,由于编译器还没有很智能,所以程序员在使用的时候有些情况下还需要关注block从栈上复制到堆上的时机,即手动调用Block_copy(比如并没有引用作用域中的自动变量等情况)。
按照Working with Blocks给出的例子,在使用block时引起强引用循环时会导致严重的内存泄漏,而大家要注意的是,循环强引用的条件是block中引用了强引用的self,而另一必要条件是self也同时引用了block。
而实际的经验也会告诉你一件事情,那就是,只要定义的block不被其他对象持有,并且此block在添加到各线程中之后已经执行完毕,则其中就算是因为self强引用了创建它的对象,也不会导致严格意义上的内存泄漏,因为在执行完毕之后,block被真正的释放(前提条件是没有对此block的显式引用且此block在添加到的各线程中也已经执行完毕了),则其对self的强引用也已经被释放了,只要此时self不要自己作去强引用这个block,就不会形成循环强引用,也不会形成永久的内存泄漏。因为在block执行完之后,其实self只要没有其他对象的强引用,是已经可以释放了的,虽然可能比原本释放的时间推后了。
所以其实大家真正怕的其实并不是在block中引用了self,因为这并不会导致循环强引用,而是在block中强引用self所可能导致的这个block未被释放所引起的self未被释放,因为在block传递过程中的任何一个环节都可以导致block被强引用,所以注意规避block中的self的强引用写法确实可以很大程度上避免内存泄漏,但这种写法本身并不一定会带来真正的内存泄漏。
注:按照Using Blocks的说法,block字面量是代表block的基于栈本地数据结构的地址。