【作者前言】:13年入圈,分享些本人工作中遇到的点点滴滴那些事儿,17年刚开始写博客,高手勿喷!以分享交流为主,欢迎各路豪杰点评改进!
1.应用场景:
Block经常被应用于设计模式,界面传值,代码块绑定,增强项目灵活性,提升代码B格等
2.实现目标:
理解Block的探索
3.代码说明:
1)其实被_ _Block修饰过的变量,修改的并非是原变量
__block int a = 10;///> 其实被__block修饰过的变量,其本身已经就GameOver了.在临时的编译区间就已经不存在了,而在block作用域代码块之中有新的区间在等着你....
NSLog(@"原本的外部作用域中的a:%p",&a);
void (^block)(void) = ^{
a ++;//这里修改的并非外部空间的变量地址,而是copy--->修改新的空间地址
NSLog(@"Block作用域中的a:%p",&a);
};
block();
NSLog(@"Block作用域处理后的a:%p",&a);
控制台输出佐证:
原本的外部作用域中的a:0x16d8dd378
Block作用域中的a:0x1d422d9d8
Block作用域处理后的a:0x1d422d9d8
2)编译过程中的底层源码探索
①在一个路径下,通过命令行创建一个testBlock.c文件
WorkZyp-MacBook-Pro:testBlock zyp$ vim testBlock.c
开启输入模式 i --->输入以上内容的c形式代码
#include "stdio.h"
int main() {
__block int a = 10;
void(^block)(void) = ^{
a++;
printf("hello testBlock");
};
block();
}
Esc--->:wq 保存退出
②gcc 编译执行
WorkZyp-MacBook-Pro:testBlock zyp$ gcc testBlock.c
③利用clang静态分析编译过程中的底层源码
WorkZyp-MacBook-Pro:testBlock zyp$ clang -rewrite-objc testBlock.c -o testBlock.cpp
到这里对编译过程的文件处理已经结束,这时在所选的路径下会出现以下三个文件:如图所示
打开testBlock.cpp文件 查看并静态的分析底层编译源码
int main() {
//对应 __block int a = 10;
__attribute__((__blocks__(byref))) __Block_byref_a_0 a = {(void*)0,(__Block_byref_a_0 *)&a, 0, sizeof(__Block_byref_a_0), 10};
/**对应
void(^block)(void) = ^{
a++;
printf("hello testBlock");
};
*/
//&a可以看出对作用域中的变量是地址的传递,以及后续是拷贝新空间对新变量进行处理
void(*block)(void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, (__Block_byref_a_0 *)&a, 570425344));
//对应 block();
((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);
}
struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
__Block_byref_a_0 *a; // by ref 可以看出是利用指针对新地址的变量进行修改
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, __Block_byref_a_0 *_a, int flags=0) : a(_a->__forwarding) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
struct __Block_byref_a_0 {
void *__isa;
__Block_byref_a_0 *__forwarding;
int __flags;
int __size;
int a;
};