int val2=10;
void(^testBlock)(void)=^{
printf("i am testBlock %d",val1);
};
val1=100;
testBlock();
struct __block_impl impl;
struct __main_block_desc_0* Desc;
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
int val1 = __cself->val1; // bound by copy
轉換前代碼:
int
global_val=1;//全局變量
static
int static_global_val=2;//靜態全局變量
int
main() {
static int
static_val=3;//靜態變量
void(^testBlock)(void)=^{
static_val=4; static_global_val=5;
global_val=6;
printf("%d,%d,%d",global_val,static_global_val,static_val);
};
testBlock();
}
|
轉換後部分代碼:
struct
__main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc; int *static_val;//靜態變量被加到結構體中 __main_block_impl_0(void*fp, struct __main_block_desc_0 *desc, int *_static_val, int flags=0) : static_val(_static_val) { impl.isa = &_NSConcreteStackBlock; impl.Flags = flags; impl.FuncPtr = fp; Desc = desc; } }; static void __main_block_func_0(struct__main_block_impl_0 *__cself) {
int *static_val = __cself->static_val;// bound by copy
(*static_val)=4;
static_global_val=5;//靜態全局變量和全局變量使用和轉換前一致。 global_val=6;// printf("%d,%d,%d",global_val,static_global_val,(*static_val)); }
|
原代碼:
//__block修飾符
int main() { __block int val=0; void(^tetsBlock)(void)=^{val=2;}; }
|
轉換之後:
struct
__Block_byref_val_0 {
void *__isa; __Block_byref_val_0 *__forwarding; int __flags; int __size; int val; };
struct
__main_block_impl_0 {
struct __block_impl impl; struct __main_block_desc_0* Desc; __Block_byref_val_0 *val; // by ref __main_block_impl_0(void*fp, struct __main_block_desc_0 *desc, __Block_byref_val_0 *_val,int flags=0) : val(_val->__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_val_0 *val = __cself->val; // bound by ref (val->__forwarding->val)=2;} static void __main_block_copy_0(struct__main_block_impl_0*dst, struct __main_block_impl_0*src) {_Block_object_assign((void*)&dst->val, (void*)src->val,8/*BLOCK_FIELD_IS_BYREF*/);} static void __main_block_dispose_0(struct__main_block_impl_0*src) {_Block_object_dispose((void*)src->val,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() { __attribute__((__blocks__(byref))) __Block_byref_val_0 val = {(void*)0,(__Block_byref_val_0 *)&val, 0,sizeof(__Block_byref_val_0),0}; void(*tetsBlock)(void)=(void(*)())&__main_block_impl_0((void*)__main_block_func_0, &__main_block_desc_0_DATA, (__Block_byref_val_0 *)&val,570425344); } |
struct
__Block_byref_val_0 {
void *__isa; __Block_byref_val_0 *__forwarding; int __flags; int __size; int val; };
|
static
void __main_block_func_0(struct__main_block_impl_0 *__cself) {
__Block_byref_val_0 *val = __cself->val; // bound by ref (val->__forwarding->val)=2;
}
|
|
轉換前代碼:
int
main() {
__block int val=0; void(^tetsBlock1)(void)=^{val=2;}; void(^testBlock2)(void)=^{val=8;}; }
|
轉換後關鍵代碼:
int
main() {
__attribute__((__blocks__(byref))) __Block_byref_val_0 val = {(void*)0,(__Block_byref_val_0 *)&val, 0,sizeof(__Block_byref_val_0),0}; void(*tetsBlock1)(void)=(void(*)())&__main_block_impl_0((void*)__main_block_func_0, &__main_block_desc_0_DATA, (__Block_byref_val_0 *)&val,570425344);//同時使用了val這個變量 void(*testBlock2)(void)=(void(*)())&__main_block_impl_1((void*)__main_block_func_1, &__main_block_desc_1_DATA, (__Block_byref_val_0 *)&val,570425344);// }
|
- Block超出變量作用域存在的理由(例如函數返回Block,返回後Block應當被釋放/廢除,卻仍能夠使用)
- __block變量的結構體成員變量__forwarding的作用
|
void(^tetsBlock1)(void)=^{};
int
main() { }
|
該Block的類:
impl.isa = &_NSConcreteGlobalBlock;
|
typedef
int (^type_block)(int);
type_block func(int rate){ return ^(int count){return rate*count;};//在非ARC環境下會報錯:Returning block that lives on the local stack,在ARC下正常。 }
|
大致流程:
源碼在對應的ARC編譯器下轉換爲
使用objc_retainBlock函數處理生成的Block對象tmp_block=objc_retainBlock(tmp_block)
而objc_retainBlock實際就是_Block_copy函數,即
/** * 將通過Block語法生成的Block賦值給變量tmp_block */
// _Block_copy函數將棧上的Block複製到堆上,複製後將堆上的地址作爲指針賦值給變量tmp_block;
tmp_block=_Block_copy(tmp_block);
// 將堆上的Block作爲OC對象註冊到autoreleasepool中並返回該對象。
return
objc_autoreleaseReturnValue(tmp_block);
|
- Cocoa框架的方法且方法名中含有usingBlock時
- Grand Central Dispatch的API
-(id)getBlockArray{
int val=10; return [[NSArray alloc]initWithObjects:^{NSLog(@"%d",val);},^{NSLog(@"%d",val);},nil]; }
使用:
//由於getBlockArray函數執行結束,棧上的Block被廢除,程序崩潰
NSArray*array= [selfgetBlockArray];
void (^aBlock)(void)=array[0];
aBlock();
|
修改後代碼:
-(id)getBlockArray{
int val=8;
return [[NSArrayalloc]initWithObjects:[^{NSLog(@"%d",val);}copy],[^{NSLog(@"%d",val);}copy],nil];
}
|
Block類
|
原存儲位置
|
複製效果
|
_NSConcreteStackBlock
|
棧區
|
從棧複製到堆
|
_NSConcreteGlobalBlock
|
程序的數據區域
|
無任何變化
|
_NSConcreteMallocBlock
|
堆區
|
引用計數增加
|
源代碼:
typedef void
(^aBlock)(void);
aBlock
oneBlock;
oneBlock =[[[oneBlock
copy]copy]copy];
該代碼可理解爲:
{
aBlock tmp=[oneBlock copy]; oneBlock=tmp; } { aBlock tmp=[oneBlock copy]; oneBlock=tmp; } { aBlock tmp=[oneBlock copy]; oneBlock=tmp; }
提示:
ARC模式下賦值時系統會自動增加強引用 當對象被賦值爲nil,對象相關的強引用將被銷燬 |
加入註釋:
oneBlock =[[[oneBlockcopy]copy]copy];
{ //將堆上的Block賦值給tmp,tmp持有強引用的Block aBlock tmp=[oneBlock copy];//執行copy後從棧到堆 //由於此時爲ARC模式,賦值後oneBlock持有堆上的Block的強引用,此時Block的持有者爲oneBlock和tmp。(在非ARC模式下爲簡單賦值,oneBlock並未持有強引用,需手動增加引用計數,否則如果tmp被釋放,oneBlock將不可使用); oneBlock=tmp; }
//超出tmp變量作用域,tmp被arc自動釋放,但Block仍被oneBlock引用,未被釋放
{
//tmp持有堆上的Block的強引用 aBlock tmp=[oneBlock copy]; //賦值給oneBlock,oneBlock原先指向的堆上的Block強引用被釋放,原先指向的堆上的Block並未廢棄(tmp強引用)。oneBlock現在持有與tmp相同的強引用。現在堆上的Block被oneBlock和tmp持有。 oneBlock=tmp; } //tmp指向的強引用被銷燬,堆上的Block由於被oneBlock持有,仍然存在。 //下面過程同上 { aBlock tmp=[oneBlock copy]; oneBlock=tmp; }
|
示意圖:
|