Block技術(shù)合集
Block的寫法及使用
iOS - __block 修飾符底層探索
先看代碼
static int number1 = 10; //全局靜態(tài)變量
// Block捕獲變量
- (void)captureVariableBlock {
static int number2 = 10; //局部靜態(tài)變量
int number3 = 10; //局部變量
__block int number4 = 10; //__block修飾的局部變量
NSMutableArray *array = [NSMutableArray arrayWithObjects:@"obj1",@"obj2", nil];
void(^captureBlock)(void) = ^ {
NSLog(@"capture Variable \n number1 = %d, \n number2 = %d, \n number3 = %d, \n number4 = %d, \n array = %@", number1, number2, number3, number4, array);
[array addObject:@"obj4"];
};
number1 = 2;
number2 = 2;
number3 = 2;
number4 = 2;
[array addObject:@"obj3"];
array = nil;
captureBlock();
}
}
打印結(jié)果:
2021-05-01 17:39:26.836630+0800 BlockDemo[14620:6891187] capture Variable
number1 = 2,
number2 = 2,
number3 = 10,
number4 = 2,
array = (
obj1,
obj2,
obj3
)
通過終端命令xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc ViewController.m -o ViewController.cpp
獲取編譯后的.cpp文件曼月,經(jīng)整理簡化后如下:
struct __ViewController__captureVariableBlock_block_impl_0 {
struct __block_impl impl;
struct __ViewController__captureVariableBlock_block_desc_0* Desc;
int *number2;
int number3;
NSMutableArray *array;
__Block_byref_number4_2 *number4; // by ref
__ViewController__captureVariableBlock_block_impl_0(void *fp, struct __ViewController__captureVariableBlock_block_desc_0 *desc, int *_number2, int _number3, NSMutableArray *_array, __Block_byref_number4_2 *_number4, int flags=0) : number2(_number2), number3(_number3), array(_array), number4(_number4->__forwarding) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
查看__ViewController__captureVariableBlock_block_impl_0
結(jié)構(gòu)體中商模,int *_number2, int _number3, NSMutableArray *_array, __Block_byref_number4_2 *_number4,
,
注意:impl.isa = &_NSConcreteStackBlock
說明該block
是棧block
可見疏唾,對于
-
oc對象
NSMutableArray *_array
,捕獲指針 -
局部靜態(tài)變量
int *_number2
捕獲指針 -
局部變量
int _number3
捕獲值 - 全局變量并未捕獲
- __block修飾的變量也是以指針形式捕獲的,并且生成了一個新的結(jié)構(gòu)體
struct __Block_byref_number4_2 {
void *__isa;
__Block_byref_number4_2 *__forwarding;
int __flags;
int __size;
int number4;
};
該結(jié)構(gòu)體有個熟悉int number4
,即我們用__block修飾的變量
這里__forwarding是指向自身的(棧Block)
一般情況下耀盗,如果我們要對block捕獲的局部變量進(jìn)行賦值操作需要添加__block修飾符调鬓,而對全局變量,靜態(tài)變量是不需要添加__block修飾符的(全局變量不需捕獲补憾,靜態(tài)變量會捕獲指針)
另外漫萄,block里訪問self或self成員變量都會去截獲self
可以看出,局部變量的值是block定義時的值盈匾,而不是block執(zhí)行時的值
block在實現(xiàn)時就會對它引用到的它所在方法中定義的棧變量進(jìn)行一次只讀拷貝腾务,然后在block內(nèi)部使用該只讀拷貝。換句話說削饵,block截獲自動變量的初始值岩瘦,或者block捕獲的是自動變量的副本
由于blick捕獲了自動變量的瞬時值,所以在執(zhí)行block語法后窿撬,即使改寫block使用的自動變量的值也不會影響block執(zhí)行時自動變量的值启昧,所以上面局部變量的值打印是10
捕獲特性
全局變量、靜態(tài)全局變量不捕獲劈伴,直接取值
局部變量是
基本數(shù)據(jù)類型
時密末,捕獲值
局部變量是oc對象
時,連同所有權(quán)修飾符一起捕獲
局部靜態(tài)變量,捕獲其指針(上述numer2打印為10)