__block修饰符(四)

2021-09-03  本文已影响0人  鄂北

一、不加__block修饰符的情况下在block内部修改变量

1、基本数据类型的auto局部变量

1-1.png

在block中无法修改基本数据类型的auto局部变量,修改时会报Variable is not assignable (missing __block type specifier)错误。block对基本数据类型的auto局部变量是值捕获,无法去修改外部的变量。

2、static修饰的基本数据类型局部变量

1-2.png
如果是static修饰的基本数据类型局部变量,在block内部就能修改外部的变量。block对static修饰的基本数据类型局部变量是指针捕获,在block内部可以修改外部变量而不报错。

3、全局变量
在block中可以修改全局变量,因为全局变量在任何作用域都可以调用,block不会对其进行捕获。

4、对象局部变量

1-4.png

block对对象局部变量是指针捕获,会对其强引用,在内部可以修改变量而不报错

二、__block的作用

1、__block可以用于解决block内部无法修改auto变量值的问题

2-1.png
从2-1中可以看到加了__block修饰后,在block内部修改age就不会报错了

2、__block不能修饰全局变量、静态变量(static)

2-2.png

3、编译器会将__block变量包装成一个对象

2-3.png

2-3加了__block

2-4.png

2-4没加__block
从2-3中可以看到,加了__block后,内部age是一个__Block_byref_age_0对象

三、__block原理

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

__Block_byref_age_0中包含了isa指针,所以变量为对象。
__forwarding是指向自己的指针
age是变量的值
block通过__forwarding指针去修改age的值

四、__block的内存管理

        __block int age = 10;
        void (^block)(void) = ^{
            NSLog(@"%d",age);
        };
        age = 20;
        block();

这里个Block里输出的age为20,因为加了__block修饰符后,编译器会将__block变量包装成一个对象,block对其是指针捕获,可以通知指针去修改值。

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

不加__block时,block是直接强引用的Person对象,但是现在是对__Block_byref_person_0进行了强引用。

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 *person;
};

__Block_byref_person_0内部才是对Person对象强引用,比没有__block多了__Block_byref_person_0这一步。__Block_byref_person_0内部还有一个__Block_byref_id_object_copy和__Block_byref_id_object_dispose,其作用跟block内部的copy和dispose一样,可以滑到上面看block的copy和dispose的讲解。

Block变量捕获详解(一)
Block的三种类型(二)
Block对象变量捕获(三)
Block循环引用(五)

上一篇 下一篇

猜你喜欢

热点阅读