那么,在block的使用注意中,你们有没有疑问说,为什么会这样呢? 说到为什么,就涉及到block的底层实现了,下面,我来介绍一下block的底层实现 - .-
使用clang命令:clang -rewrite-objc main.m,把刚才的main.m编译为c++文件. 编译好之后,你会发现文件夹多了一个main.cpp文件,这个就是编译出来的c++文件了,好,我们open一下.
*打开之后你会发现,哇塞,有10W+行代码...- -! 好,我们拖到最下面,编译结果如下:
#---------------编译器内会将block内部生成对应的函数--------------------------------------------------------- struct __main_block_impl_0 { struct __block_impl impl; struct __main_block_desc_0* Desc; int a; __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int _a, int flags=0) : a(_a) { impl.isa = &_NSConcreteStackBlock; impl.Flags = flags; impl.FuncPtr = fp; Desc = desc; } }; #---------------编译器内会将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_03_d2zvdhkx4pg_j_03cp176fvw0000gp_T_main_6df904_mi_0, a); } #------------------------------------------------------------------------ static struct __main_block_desc_0 { size_t reserved; size_t Block_size; } __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0)}; int main(int argc, const char * argv[]) { /* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool; int a = 10; void (*myBlock)() = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, a)); a = 50; ((void (*)(__block_impl *))((__block_impl *)myBlock)->FuncPtr)((__block_impl *)myBlock); } return 0; } 不难发现,我们看到了void (*myBlock)() = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, a));这一句,就是block块里面的,是把a的值传进去了,那么,在外面修改a的值,外面修改它的值是不知道的,a的值是不会改变的!再深一层讲,block就是&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, a));这个家伙的地址,这个就是一个c++结构体. #所以,说白了,block的本质就是一个指向结构体的一个指针那么,这个结构体是什么呢?拉上去可以看到:
struct __main_block_impl_0 { struct __block_impl impl; struct __main_block_desc_0* Desc; int a; __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int _a, int flags=0) : a(_a) { impl.isa = &_NSConcreteStackBlock; impl.Flags = flags; impl.FuncPtr = fp; Desc = desc; } }; 我们需要知道的是: 这个block块这是一个结构体 void (*myBlock)() = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, a));对应着上面的这一段结构体(就是下面这一段)
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int _a, int flags=0) : a(_a) {} 传得参数都是对应的,留意a是传到_a,后面一句a(_a)按照c++的语法,相当于把_a的值10赋值给a,那么a就是10.就是结构体里面的a就是10.接着,留意参数(__block_impl *)myBlock)->FuncPtr对应impl.FuncPtr = fp;就是fp
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int _a, int flags=0) : a(_a) { impl.isa = &_NSConcreteStackBlock; impl.Flags = flags; impl.FuncPtr = fp; Desc = desc;那么,就是第一个参数的*fp,所以就相当于我们的block块的第一个参数__main_block_func_0,调了一下这个函数
void (*myBlock)() = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, a));调用函数__main_block_func_0,来到下面这个代码块调用了这个函数
static void __main_block_func_0(struct __main_block_impl_0 *__cself) { int a = __cself->a; // bound by copy NSLog((NSString *)&__NSConstantStringImpl__var_folders_03_d2zvdhkx4pg_j_03cp176fvw0000gp_T_main_6df904_mi_0, a); }把block传进去以后访问int a = __cself->a;,那么此时a就是10,打印出来就是10
好,我们看一下下面的就改了呢?
__block int a = 10; void (^myBlock)() = ^{ NSLog(@"a = %i", a); }; a = 20; myBlock(); 输出结果: 20下面是编译结果代码:
struct __Block_byref_a_0 { void *__isa; __Block_byref_a_0 *__forwarding; int __flags; int __size; int a; }; 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; } }; static void __main_block_func_0(struct __main_block_impl_0 *__cself) { __Block_byref_a_0 *a = __cself->a; // bound by ref NSLog((NSString *)&__NSConstantStringImpl__var_folders_03_d2zvdhkx4pg_j_03cp176fvw0000gp_T_main_642b4a_mi_0,(a->__forwarding->a)); } static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {_Block_object_assign((void*)&dst->a, (void*)src->a, 8/*BLOCK_FIELD_IS_BYREF*/);} static void __main_block_dispose_0(struct __main_block_impl_0*src) {_Block_object_dispose((void*)src->a, 8/*BLOCK_FIELD_IS_BYREF*/);} static struct __main_block_desc_0 { size_t reserved; size_t Block_size; void (*copy)(struct __main_block_impl_0*, struct __main_block_impl_0*); void (*dispose)(struct __main_block_impl_0*); } __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0), __main_block_copy_0, __main_block_dispose_0}; int main(int argc, const char * argv[]) { /* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool; __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 (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, (__Block_byref_a_0 *)&a, 570425344)); (a.__forwarding->a) = 20; ((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block); } return 0; } 我们发现,a传进去的是地址,那么结果显而易见了!转载于:https://www.cnblogs.com/ljwiOS/p/5544313.html
相关资源:JAVA上百实例源码以及开源项目