iOS 底层学习13 -- block访问oc对象本质

2020-08-21  本文已影响0人  恋空K

在ARC环境下面,编译器会根据一些情况自动把栈blcok copy到堆上面去。


ARC环境下block作为函数返回值

ARC环境下,block只要被强指针指着,就会自动做copy操作。


block被强指针指着,所以该block是堆blcok,要是MRC环境下,该blcok就是栈block
ARC环境下,这种情况是栈block
这种没有访问auto变量的block,是全局block
这些block也会执行copy操作,变成堆block

此时perosn对象在断点之前被释放
此时person对象没有被释放

auto变量本身是什么类型,被block捕获进去后就是什么类型。比如原来是int类型,捕获block里面去后,就是int类型。如果有static修饰,int类型被捕获进去后就是int *类型。
MJPerson *类型被捕获进去后就是MJPerson *类型。如果用static修饰了MJPerson *,被block捕获进去后就是MJPerson * *类型。

只要block在,person指针就在,这样person这个强指针指向的person内存就在,不会释放
这是MRC环境下,间接说明栈空间的block不会对外面的person进行类似强引用的操作
MRC环境下,对block进行copy操作后,走到断点的时候,person没有释放

由上图得知,MRC环境下,堆空间的block会在block里面对person对象做一次retain操作,当block要销毁的时候,又会回来对person进行release操作。
由此得出一个结论,不管是MRC还是ARC,栈空间上面的block,是不会去拥有外面那些对象的,是不会去持有那些对象的,不能保住它的命,也就是不会强引用,堆空间的block,是有能力去保住外面对象的命的,换成ARC的说法就是强引用,但是MRC下是没有强引用这种说法的,只有reatin保住它的命,release释放掉它。但是当堆空间的block自己销毁的时候,也会对里面用到的person对象进行一次release操作。

ARC环境下,过掉了28行,block被销毁了,所以block会对它刚刚引用的person也会进行一次释放操作
ARC环境下

strong 修饰符是oc对象的默认修饰符
id arr = [[NSArray alloc] init] 等同于 id __strong arr = [[NSArray alloc] init]

此时生成的c文件对应下图
此时person变成了__weak 修饰的弱引用 此时生成的c文件对应下图
此时person是__strong 修饰的强引用 此时生成的c文件对应下图
此时person是__strong 修饰的强引用

当初访问外面auto变量是以什么指针访问它,到时候它在block的结构体里面就是什么指针类型。但是如果block是栈block的话,不管auto变量指针是什么都没用。
如果block是在栈上,不管是MRC环境还是ARC环境,block内部都不会强引用外面的auto变量


ARC环境下,block没有被强引用,所以该block是栈block,所以该block对person是没有强引用的 不管这里是strong还是weak,只要block是栈上的,它都不会强引用外面的auto变量 当block进行一次copy操作的时候,就会自动调用下图中的copy函数
图中的_block_object_assign函数

图中的_block_object_assign函数的作用:这个函数(也就是这个操作),会自动根据block的结构体里面,*person是__strong类型的指针还是__weak类型的指针,对person对象产生强引用或者弱引用。也就是说执行完这个函数:block里面写的是__strong修饰的指针,那这个指针就会对外面的person对象产生强引用,如果是__weak修饰的指针,那这个指针对外面的person对象是弱引用。


该函数在block从堆中移除的时候调用
这个函数里面做了:相当于对perosn进行一次release操作。也就是释放当初被block引用的那些变量。
总结

总结:如果block是在栈空间的,不管外面访问的auto变量是强引用也好,还是弱引用也好,总之栈block都不会对它进行强引用,既都是弱引用。如果block是在堆空间的,那你是通过弱引用访问这个对象,还是通过强引用访问这个对象,效果就不一样了,如果强引用访问外面的auto变量,那block结构体里面生成的引用auto变量的指针也是强引用,所以block调用copy的时候,该指针会强引用外面的auto变量。反之要是weak就是弱引用。

如果是MRC环境,_block_object_assign函数就决定要不要对访问的外面的auto变量就行retain操作。不管是强引用还是弱引用_block_object_assign函数都会调用的。(只要block拷贝到堆上面,就会自动调用_block_object_assign函数)

补充:


MRC环境下

此时person不会释放,因为person强持有testBlock,testBlock里面强持有person
不管是MRC环境还是ARC环境:属性block,先看block是什么类型,再看block属性用什么关键词修饰,才能决定block的最终的类型(block作为属性,strong效果和copy效果一样,都会对block进行拷贝操作,但是我们习惯于用copy,weak修饰block,block不会进行拷贝操作)。


MRC环境下,因为block手动调用了copy,所以需要手动release block,block才会释放,block了释放了,才会放弃对person的强引用
MRC环境下,此时block没有手动释放,所以person一直被block强持有,person也不会释放
MRC环境下,此时block没有手动释放,但是block没有强持有perosn,所以perosn还是会被释放,block是没有释放的,因为此时blcok已经被copy到堆区了
上一篇 下一篇

猜你喜欢

热点阅读