iOS-block什么时候需要对变量使用__block

 

什么时候需要对变量使用__block?

__block可以用于解决block内部无法修改auto变量值的问题。__block不能修饰全局变量、静态变量(static)。

 

__block用来赋值场景(对象类型)(使用场景修改auto变量值)

//赋值场景
NSMutableArray *__block array = nil;

void(^Block)(void) = ^{
    array = [NSMutableArray array];
};

Block();
    

 

使用场景修改auto变量值(基本数据类型)和底层实现

__block int age = 10;
__block NSObject *obj = [[NSObject alloc] init];

void (^block)(void) = ^{
    obj = nil;
    age = 20;
};

上面的代码会被编译为:

struct __main_block_impl_0 {
  struct __block_impl impl;
  struct __main_block_desc_0* Desc;
  __Block_byref_obj_1 *obj; // by ref
  __Block_byref_age_0 *age; // by ref
  __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, __Block_byref_age_0 *_age, int flags=0) : age(_age->__forwarding) {
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }
};

struct __Block_byref_age_0 {
  void *__isa;
__Block_byref_age_0 *__forwarding;
 int __flags;
 int __size;
 int age;
};

struct __Block_byref_obj_1 {
  void *__isa;
__Block_byref_obj_1 *__forwarding;
 int __flags;
 int __size;
 //内存管理
 void (*__Block_byref_id_object_copy)(void*, void*);
 void (*__Block_byref_id_object_dispose)(void*);
 NSObject  *obj;
};

//实际执行的block代码
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
  __Block_byref_obj_1 *obj = __cself->obj; // bound by ref
  __Block_byref_age_0 *age = __cself->age; // bound by ref

            (obj->__forwarding->obj) = __null;
            (age->__forwarding->age) = 20;
        }

可见,__block修饰的变量会被包装成一个对象。

 

问题:block在修改NSMutableArray时,需不需要添加__block?

//block里面添加数据 不需要使用__block 因为这是对地址进行的操作
NSMultableArray *array = [NSMultableArray array];

void(^Block)() = ^{
    [array addObject:@"1"];
};

Block();

我们给array添加元素,是使用这个地址,而不是修改这个地址, 但是如果我们array = nil这样才会报错,所以如果赋值的话需要用__block

 

__block变量的内存管理

当block在栈上时,并不会对__block变量产生强引用。

当block被copy到堆时:

  • 会调用block内部的copy函数
  • copy函数内部会调用_Block_object_assign函数
  • _Block_object_assign函数会对__block变量形成强引用(retain)[仅ARC, MRC不会retain]

当block从堆中移除时:

  • 会调用block内部的dispose函数
  • dispose函数内部会调用_Block_object_dispose函数
  • _Block_object_dispose函数会自动释放引用的__block变量(release)

 

posted @ 2021-06-29 19:51  俊华的博客  阅读(587)  评论(0编辑  收藏  举报