XB_block(3)

1.__block的内存管理

我们已经知道,__block修饰符会把auto变量包装成一个对象

  • 1.当block在栈上时,并不会对__block变量产生强引用
  • 2.当block被copy到堆时,会调用block内部的copy函数,copy函数内部会调用_Block_object_assign函数, _Block_object_assign函数会对__block变量形成强引用(retain),注意这里是__block变量,也就是类似struct __Block_byref_age_这个的结构体,而不是内部的age。

 

 如果Block0先使用了__block变量,会将__block变量复制到堆空间,Block1后使用__block变量,不会再次复制__block到堆空间。

  • 3.当block从堆中移除时,会调用block内部的dispose函数,dispose函数会调用_Block_object_dispose函,_Block_object_dispose函数会自动释放引用的__block变量(release)。
  • 4.关于__block的__forwarding指针

也就解释了,在block外部调用栈上的__block变量的时候,其实访问了堆中的__block变量

  •  

2.对象类型的auto变量与__block修饰的变量对比

  • 当block在栈上的时候对它们都不会产生强引用
  • 当block拷贝到堆上时,都会通过copy函数来处理它们

     1.>  __block变量(假设变量名叫做a),底层处理如下:

_Block_object_assign((void*)&dst->a, (void*)src->a, 8/*BLOCK_FIELD_IS_BYREF*/); 

      2.>对象类型的auto变量(假设变量名叫做p) ,底层处理如下:

_Block_object_assign((void*)&dst->p, (void*)src->p, 3/*BLOCK_FIELD_IS_OBJECT*/);
  • 当block从堆上移除时,都会通过dispose函数来释放它们

     1.>__block变量(假设变量名叫做a),底层处理如下:

  • _Block_object_dispose((void*)src->a, 8/*BLOCK_FIELD_IS_BYREF*/);

     2.>对象类型的auto变量(假设变量名叫做p),底层处理如下:

_Block_object_dispose((void*)src->p, 3/*BLOCK_FIELD_IS_OBJECT*/);

其实就是BLOCK_FIELD的不同

3.被__block修饰的对象类型的auto变量

  • 当__block变量在栈上时,不会对指向的对象产生强引用
  • 当__block变量被copy到堆时,会调用__block变量内部的copy函数,copy函数内部会调用_Block_object_assign函数, _Block_object_assign函数会根据所指向对象的修饰符(__strong、__weak、__unsafe_unretained)做出相应的操作,形成强引用(retain)或者弱引用(注意:这里仅限于ARC时会retain,MRC时不会retain,这里的强弱引用是指向的对象,而不是__block变量,__block变量一直是强引用的,与修饰符无关)。

   强引用下生成的底层结构

  __block Person *person = [[Person alloc] init];;
        person.age = 10;
        MyBlock block = ^{
            NSLog(@"age is %d", person.age);
        };


//xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc -fobjc-arc -fobjc-runtime=ios-8.0.0 main.m  生成C++文件
struct __Block_byref_person_0 {
  void *__isa;
__Block_byref_person_0 *__forwarding;
 int __flags;
 int __size;
 void (*__Block_byref_id_object_copy)(void*, void*);
 void (*__Block_byref_id_object_dispose)(void*);
 Person *__strong person;
};

弱引用下生成的底层结构

Person *person = [[Person alloc] init];
        __block __weak typeof(person) weakPerson = person;
        person.age = 10;
        MyBlock block = ^{
            NSLog(@"age is %d", weakPerson.age);
        };



//xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc -fobjc-arc -fobjc-runtime=ios-8.0.0 main.m  生成C++文件
typedef void(*MyBlock)(void);
struct __Block_byref_weakPerson_0 {
  void *__isa;
__Block_byref_weakPerson_0 *__forwarding;
 int __flags;
 int __size;
 void (*__Block_byref_id_object_copy)(void*, void*);
 void (*__Block_byref_id_object_dispose)(void*);
 Person *__weak weakPerson;
};

 

  • 当__block变量从堆上移除时,会调用block内部的dispose函数,dispose函数会调用_Block_object_dispose函,_Block_object_dispose函数会自动释放引用的__block变量(release)。

注意:这里与被__block修饰的非对象类型的auto变量的唯一的区别就是在copy到堆上的时候,会根据对象修饰符对__block变量中的引用对象做出强弱引用操作。

3.解决循环引用

1.在ARC环境下使用__weak、__unsafe_unretained修饰符解决,MRC环境下使用__unsafe_unretained修饰符,不能使用__weak

2.在ARC和MRC环境下都可以使用__block解决,但条件是必须要调用block

原理如下

总结:

对于引用对象类型的__block变量,一定要搞清楚__block变量与引用的对象不是同一个东西,__block变量持有引用的对象。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值