那么,在block的使用注意中,你们有没有疑问说,为什么会这样呢?
说到为什么,就涉及到block的底层实现
了,下面,我来介绍一下block的底层实现 - .-
int a = 10;
void (^myBlock)() = ^{
NSLog(@"a = %i", a);
} myBlock();
输出结果: 10
__block int a = 10;
void (^myBlock)() = ^{
NSLog(@"a = %i", a);
};
a = 20;
myBlock();
输出结果: 20
a = 50;
,那么为什么并没有把a的值改掉呢?使用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的值是不会改变的!&__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;
}
};
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)
按照c++的语法,相当于把_a
的值10赋值给a
,那么a
就是10.就是结构体里面的a
就是10.((void (*)(__block_impl *))((__block_impl *)myBlock)->FuncPtr)((__block_impl *)myBlock);
接着,留意参数(__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
传进去的是地址,那么结果显而易见了!全局变量a
,或者是加__block
修饰的.或者是加status
修饰的,都是地址传递.好吧,明白了上面,相信对block有更进一步的认识了,有不对的地方大家可以交流一下...
------make by LJW 转载请注明出处-------