「这是我参与11月更文应战的第27天,活动概况检查:2021毕竟一次更文应战」。

__block 修饰符的运用

__block可以用于处理block内部无法批改auto变量值的问题

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

编译器会将__block变量包装成一个方针

以下代码的是否编译经过,可以的话输出效果是什么

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

效果:无法编译 miss__block
源码如下

//main函数
int main(int argc, const char * argv[]) {
    /* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool; 
        int a = 10;
        void (*block)() = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, a));
    }
    return 0;
}
//block实行地址
  static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
  int a = __cself->a; // bound by copy
  NSLog((NSString *)&__NSConstantStringImpl__var_folders_kh_0rp73c0s2mvfp5gjf25j5y6h0000gn_T_main_1a12fa_mi_0,a);}

block实行的时分,内部是 __main_block_func_0 函数,而a的声明,是在main函数,两个函数彼此独立,关于他们来说,a都是一个局部变量,而且两个函数中都对a初始化,两个函数的中a不是同一个,那怎么可以在 实行函数中,批改main函数中的局部变量呢,所以编译报错!
如何改?

方案一:运用static

static int a = 10;
void (block)() = {
    a = 20;
    NSLog(@"a = %d",a);
};

由于static修饰的auto变量,毕竟在block中进行的不是值传递,而是地址传递,措意实行函数中的a 和 main 函数中的a,是同一个地址 ==> 等于同一个a,所以可以批改,输出20

但是运用static,就会变成静态变量,永远在内存中
方案二: 运用__blcok

__block auto int a = 10;
void (block)() = {
    a = 20;
    NSLog(@"a = %d",a);
};
struct __main_block_impl_0 {
  struct __block_impl impl;
  struct __main_block_desc_0* Desc;
  __Block_byref_a_0 *a; // by ref ==> auto的话,是int a__block,变成方针了
}
struct __Block_byref_a_0 {
  void *__isa;
__Block_byref_a_0 *__forwarding;==> 指向自己的结构体
 int __flags;
 int __size;
 int a; ==> 10在这里
};

a = 20;毕竟转成 (a->__forwarding->a) = 20;

解说下:__forwarding 是指向结构体本身的指针,等价于a本身,其实便是经过a的结构体指针,拿到里面的成员a,再对他赋值

指针传递,所以可以批改 auto 变量,经过block,间接引用 auto 变量

iOS block内存办理

__block中的 _ forwarding 指针

内存复制的时分,假如block从栈被copy到堆上,肯定也希望内部的变量一同存储到堆上(让变量的生命周期可控,才不会被回收)

参加变量a在栈上,在栈上的指针,指向堆上的 block,堆上的block的 forwarding指向他自己,就可以保证,批改&获取的变量,都是堆上的变量

毕竟,__block指向的变量,是指向堆上的

iOS block内存办理

一旦block里面要用到/访问某个方针,那就要对相应的方针进行内存办理

当block在栈上的时分,是不会对__block变量进行强引用的
当block在堆上的时分,会调用block内部的copy函数,而copy函数内部会调用_Block_object_assign函数,_Block_object_assign函数会根据auto变量的修饰符 ( strong、 weak、unsafe_unretained ) 做出对应的操作,看对内部auto变量进行强引用还是弱引用

方针类型的auto变量和__block变量
当block在栈上的时分,对他们都不会产生强引用,永远都是弱引用,
当block被copy到堆上来的时分,都会经过copy函数来处理它们_Block_object_assign-》1.weak 2.strong

iOS block内存办理

移除:
当block从堆中移除的时分,会调用block内部的dispose函数,而dispose函数内部会调用_Block_objcet_dispose函数,_Block_object_dispose 类似于 release,会对auto变量进行主动开释(当引用计数器=0的时分 )
上图

iOS block内存办理

Tips:
在运用clang转化OC为C++代码时,可能会遇到以下问题
cannot create __weak reference in file using manual reference

处理方案:支撑ARC、指定运行时系统版别,比如
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc -fobjc-arc -fobjc-runtime=ios-8.0.0 main.m