本文主要介绍__forwarding
指针,retain
、release
以及copy
对三种block的影响。
©原创文章,转载请注明出处!
__forwarding
在前文代码片段codeF中提到编译器为__block变量blockArr
合成的结构体struct __Block_byref_blockArr_0
,
在该结构体中有一个指向结构自身类型的指针__Block_byref_blockArr_0 *__forwarding
。
ok,问题出来,这些__forwarding
指针的作用是什么呢?
前面我们讲到__block变量会随block copy到heap而同样被copy到heap,因此,在此情况下就存在同时访问stack上和heap上__block变量的情况:
很明显,第一次访问的var
位于heap上,第二次访问的var
位于stack上,因此,如果不采用特殊机制,将导致var
的值不正确。
嗯,这就是__forwarding指针的使命所在——确保能正确的访问__block变量。
当block变量从stack到copy到heap上时,stack上的forwarding被修改为指向heap上的block变量,通过该机制,使得无论是在stack上还是heap上都能访问到同一个block变量。
前文代码片段codeH中的第44行就是修改stack上block变量的forwarding指针,使其指向heap上的__block变量:_Block_assign(src->forwarding, (void **)destp)
。
最后再亮出我们的看家法宝——【图】:
block与retain、release以及copy
对block来说,release
与Block_release
、copy
与Block_copy
等同。
还是用源码说话吧:
1 | void _Block_release(void *arg) |
由_Block_release
的源码可以得出如下结论:
block在其内部标记
flags
中保存了自己的引用计数,且引用计数占用flags
的前16位(BLOCK_REFCOUNT_MASK = 0xffff)(第8行);release NSConcreteMallocBlock类型的block,会将其引用计数-1,当引用计数<=0时,先调用block的dispose函数,再释放block本身(第13~17行);
release NSConcreteGlobalBlock或NSConcreteStackBlock类型的block没有任何实质操作。
block retain操作没有相关的源码,但从效果来看:
retain NSConcreteMallocBlock类型的block,其引用计数会+1;
retain NSConcreteGlobalBlock或NSConcreteStackBlock类型的block没有任何实质操作.
1 | void *_Block_copy(const void *arg) |
由Block_copy的源码可以看出:
NSConcreteMallocBlock类型的block在copy时引用计数+1;
NSConcreteGlobalBlock类型的block在copy时直接返回;
NSConcreteStackBlock类型的block在copy时才会进行真正的copy操作。
看个有趣的例子:
应该很清楚了,不用多说。
ok,最后总结一下: