说明:
<1>阅读本问,请参照block前述文章加以理解;
<2>环境:ARC;
<3>变量类型:基本数据类型或者对象类型的auto局部变量;
一、三种情形
//代码
void test1() { int num = 10; __block int age = 20; Person *per = [[Person alloc] init]; void(^block)(void) = ^{ NSLog(@"%d %d %p", num, age, per); }; block(); }
//打印
2019-01-16 15:42:38.974947+0800 MJ_TEST[2405:192414] 10 20 0x100654220 2019-01-16 15:42:38.975258+0800 MJ_TEST[2405:192414] -[Person dealloc] Program ended with exit code: 0
//clang:xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc -fobjc-arc -fobjc-runtime=ios-9.0.0 main.m
struct __Block_byref_age_0 { void *__isa; __Block_byref_age_0 *__forwarding; int __flags; int __size; int age; }; struct __test1_block_impl_0 { struct __block_impl impl; struct __test1_block_desc_0* Desc; int num; Person *__strong per; __Block_byref_age_0 *age; // by ref __test1_block_impl_0(void *fp, struct __test1_block_desc_0 *desc, int _num, Person *__strong _per, __Block_byref_age_0 *_age, int flags=0) : num(_num), per(_per), age(_age->__forwarding) { impl.isa = &_NSConcreteStackBlock; impl.Flags = flags; impl.FuncPtr = fp; Desc = desc; } }; static void __test1_block_copy_0(struct __test1_block_impl_0*dst, struct __test1_block_impl_0*src) {_Block_object_assign((void*)&dst->age, (void*)src->age, 8/*BLOCK_FIELD_IS_BYREF*/);_Block_object_assign((void*)&dst->per, (void*)src->per, 3/*BLOCK_FIELD_IS_OBJECT*/);} static void __test1_block_dispose_0(struct __test1_block_impl_0*src) {_Block_object_dispose((void*)src->age, 8/*BLOCK_FIELD_IS_BYREF*/);_Block_object_dispose((void*)src->per, 3/*BLOCK_FIELD_IS_OBJECT*/);} static struct __test1_block_desc_0 { size_t reserved; size_t Block_size; void (*copy)(struct __test1_block_impl_0*, struct __test1_block_impl_0*); void (*dispose)(struct __test1_block_impl_0*); } void test1() { int num = 10; __attribute__((__blocks__(byref))) __Block_byref_age_0 age = {(void*)0,(__Block_byref_age_0 *)&age, 0, sizeof(__Block_byref_age_0), 20}; Person *per = ((Person *(*)(id, SEL))(void *)objc_msgSend)((id)((Person *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("Person"), sel_registerName("alloc")), sel_registerName("init")); void(*block)(void) = ((void (*)())&__test1_block_impl_0((void *)__test1_block_func_0, &__test1_block_desc_0_DATA, num, per, (__Block_byref_age_0 *)&age, 570425344)); ((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block); }
分析:根据前述文章可知
<1>ARC模式下,block对象(等号右边大括号)被强指针(等号左边)变量持有(默认为strong)时,系统会自动将block对象从栈区copy到堆区;
<2>当访问实例对象或者__block修饰的基础数据类型变量时,block对象结构体中自动会增加两个函数指针——copy和dispose,分别指向__test1_block_copy_0函数和__test1_block_dispose_0函数;
<3>__block修饰的基础数据类型的变量,系统会自动生成一个新的对象(__Block_byref_age_0),block对象通过该新的对象指针变量(__Block_byref_age_0 *age)来访问基础数据类型变量(int age);
<4>num:直接被block捕捉到其结构体内部,随block一起copy到堆区;其随block对象本身一起销毁(不管是栈区的block还是堆区的block);
<5>per:类对象的访问,当block对象被copy到堆区时,block对象会通过copy函数指针来调用__test1_block_copy_0函数完成对per对象的拷贝;同时此时堆区的block对象会根据该类对象的类型(strong还是weak)来决定对其强引用还是弱引用;
说明:所谓的强引用,是指指针指向某个对象(