「这是我参与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 变量
__block中的 _ forwarding 指针
内存复制的时分,假如block从栈被copy到堆上,肯定也希望内部的变量一同存储到堆上(让变量的生命周期可控,才不会被回收)
参加变量a在栈上,在栈上的指针,指向堆上的 block,堆上的block的 forwarding指向他自己,就可以保证,批改&获取的变量,都是堆上的变量
毕竟,__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
移除:
当block从堆中移除的时分,会调用block内部的dispose函数,而dispose函数内部会调用_Block_objcet_dispose函数,_Block_object_dispose 类似于 release,会对auto变量进行主动开释(当引用计数器=0的时分 )
上图
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