国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發(fā)設計 > 正文

block解析-局部變量

2019-11-14 20:11:52
字體:
來源:轉載
供稿:網友

局部變量

block內使用局部變量,一般都是截獲變量(只讀),截獲離block初始化最近的一次的值。
引用官方文檔:
  1. Stack (non-static) variables local to the enclosing lexical scope are captured as const variables.Their values are taken at the point of the block exPRession within the program. In nested blocks, the value is captured from the nearest enclosing scope. 
 
我們做一個測試,了解一下原理
代碼如下:
-(void )test3{    NSString *_person2=@"person2";    NSMutableArray *_listTest=[[NSMutableArray alloc]init];    //初始值    NSLog(@"init _person2:%@,%p",_person2,_person2);    NSLog(@"init _listTest:%@,%p",_listTest,_listTest);    void (^myBlock)(int) = ^(int num) {        //block內賦值        //        _weakPerson2=@"person22";        NSLog(@"excuteing _person2:%@,%p",_person2,_person2);        NSLog(@"excuteing _listTest:%@,%p",_listTest,_listTest);    };    //修改前賦值    _person2=@"person22";    [_listTest addObject:@"1212"];    NSLog(@"excutebefore _person2:%@,%p",_person2,_person2);    NSLog(@"excutebefore _listTest:%@,%p",_listTest,_listTest);    myBlock(1);    //block執(zhí)行后    NSLog(@"excuteafter _person2:%@,%p",_person2,_person2);    NSLog(@"excuteafter _listTest:%@,%p",_listTest,_listTest);}

 輸出一下結果:

2014-07-29 11:05:29.460 Test[2540:60b] init _person2:person2,0xb18ec2014-07-29 11:05:29.463 Test[2540:60b] init _listTest:(),0x17d985602014-07-29 11:05:29.464 Test[2540:60b] excutebefore _person2:person22,0xb193c2014-07-29 11:05:29.465 Test[2540:60b] excutebefore _listTest:(    1212),0x17d985602014-07-29 11:05:29.467 Test[2540:60b] excuteing _person2:person2,0xb18ec2014-07-29 11:05:29.468 Test[2540:60b] excuteing _listTest:(    1212),0x17d985602014-07-29 11:05:29.470 Test[2540:60b] excuteafter _person2:person22,0xb193c2014-07-29 11:05:29.471 Test[2540:60b] excuteafter _listTest:(    1212),0x17d98560
 從日志可以看出:block內部對于可變、不可變的變量都無法修改,而且
  1. 在block初始化后對于NSString 變量  _person2 的修改,并沒有同步到block內部,因為這時block外部的變量_person2指針重新指向另外一塊內存
  2. 在block初始化后對于NSMutableArray變量 _listTest 的修改,同步到block內部,因為這時block外部的變量 _listTest 指針指向的內存地址沒有變,只是對這塊內存的值進行了操作。
我們可以借助  clang -rewrite-objc 轉換.c文件得到.cpp文件,也可以轉換.m也可以得到cpp文件(可能會有些報錯)
以下是部分轉換后的代碼
//這里就是block對象的結構
//imp:函數指針對象,FuncPtr指向具體block實現的函數
//_person2:截獲的變量
//isa、flags、funcptr、desc后面會說道。
struct __block_impl {  void *isa;  int Flags;  int Reserved;  void *FuncPtr;};
struct __KDBlockTest__test3_block_impl_0 {  struct __block_impl impl;  struct __KDBlockTest__test3_block_desc_0* Desc;  NSString *_person2;  NSMutableArray *_listTest;  __KDBlockTest__test3_block_impl_0(void *fp, struct __KDBlockTest__test3_block_desc_0 *desc, NSString *__person2, NSMutableArray *__listTest, int flags=0) : _person2(__person2), _listTest(__listTest) {    impl.isa = &_NSConcreteStackBlock;    impl.Flags = flags;    impl.FuncPtr = fp;    Desc = desc;  }};

//block實現的函數
static void __KDBlockTest__test3_block_func_0(struct __KDBlockTest__test3_block_impl_0 *__cself, int num) {  NSString *_person2 = __cself->_person2; // bound by copy  NSMutableArray *_listTest = __cself->_listTest; // bound by copy        NSLog((NSString *)&__NSConstantStringImpl__var_folders_5l_2l25j3tn0wl_3zy1hpsq1rhc0000gp_T_KDBlockTest_6946c5_mi_4,_person2,_person2);        NSLog((NSString *)&__NSConstantStringImpl__var_folders_5l_2l25j3tn0wl_3zy1hpsq1rhc0000gp_T_KDBlockTest_6946c5_mi_5,_listTest,_listTest);    }

 

//block對象的描述信息(大小等等)
static struct __main1_block_desc_0 {  size_t reserved;  size_t Block_size;} __main1_block_desc_0_DATA = { 0, sizeof(struct __main1_block_impl_0)};
//這是objc測試函數test
static void _I_KDBlockTest_test3(KDBlockTest * self, SEL _cmd) {    NSString *_person2=(NSString *)&__NSConstantStringImpl__var_folders_5l_2l25j3tn0wl_3zy1hpsq1rhc0000gp_T_KDBlockTest_6946c5_mi_1;    NSMutableArray *_listTest=((id (*)(id, SEL))(void *)objc_msgSend)((id)((id (*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("NSMutableArray"), sel_registerName("alloc")), sel_registerName("init"));    NSLog((NSString *)&__NSConstantStringImpl__var_folders_5l_2l25j3tn0wl_3zy1hpsq1rhc0000gp_T_KDBlockTest_6946c5_mi_2,_person2,_person2);    NSLog((NSString *)&__NSConstantStringImpl__var_folders_5l_2l25j3tn0wl_3zy1hpsq1rhc0000gp_T_KDBlockTest_6946c5_mi_3,_listTest,_listTest);    void (*myBlock)(int) = (void (*)(int))&__KDBlockTest__test3_block_impl_0((void *)__KDBlockTest__test3_block_func_0, &__KDBlockTest__test3_block_desc_0_DATA, _person2, _listTest, 570425344);    _person2=(NSString *)&__NSConstantStringImpl__var_folders_5l_2l25j3tn0wl_3zy1hpsq1rhc0000gp_T_KDBlockTest_6946c5_mi_6;    ((void (*)(id, SEL, id))(void *)objc_msgSend)((id)_listTest, sel_registerName("addObject:"), (id)(NSString *)&__NSConstantStringImpl__var_folders_5l_2l25j3tn0wl_3zy1hpsq1rhc0000gp_T_KDBlockTest_6946c5_mi_7);    NSLog((NSString *)&__NSConstantStringImpl__var_folders_5l_2l25j3tn0wl_3zy1hpsq1rhc0000gp_T_KDBlockTest_6946c5_mi_8,_person2,_person2);    NSLog((NSString *)&__NSConstantStringImpl__var_folders_5l_2l25j3tn0wl_3zy1hpsq1rhc0000gp_T_KDBlockTest_6946c5_mi_9,_listTest,_listTest);    ((void (*)(__block_impl *, int))((__block_impl *)myBlock)->FuncPtr)((__block_impl *)myBlock, 1);    NSLog((NSString *)&__NSConstantStringImpl__var_folders_5l_2l25j3tn0wl_3zy1hpsq1rhc0000gp_T_KDBlockTest_6946c5_mi_10,_person2,_person2);    NSLog((NSString *)&__NSConstantStringImpl__var_folders_5l_2l25j3tn0wl_3zy1hpsq1rhc0000gp_T_KDBlockTest_6946c5_mi_11,_listTest,_listTest);}

 

簡單分析block截獲變量:

 1).block初始化
void (*myBlock)(int) = (void (*)(int))&__KDBlockTest__test3_block_impl_0((void *)__KDBlockTest__test3_block_func_0, &__KDBlockTest__test3_block_desc_0_DATA, _person2, _listTest, 570425344);

 

傳入了參數:函數指針、block描述、外部變量 _person2 和 _listTest,這時候在block內部對 _person2、_listTest 進行了引用
: _person2(__person2), _listTest(__listTest)

 

  1. 在block初始化后,我們對 _person2 做了修改,重新指向了 0xb193c 這塊內存,但是不會影響block結構體成員_person2,因為成員 _person2 指向的是 0xb18ec。
  2. 向 _listTest 數組中添加了一個元素,并沒有改變它的內存地址,依然還是 0x17d98560 
_person2=(NSString *)&__NSConstantStringImpl__var_folders_5l_2l25j3tn0wl_3zy1hpsq1rhc0000gp_T_KDBlockTest_6946c5_mi_6;    ((void (*)(id, SEL, id))(void *)objc_msgSend)((id)_listTest, sel_registerName("addObject:"), (id)(NSString *)&__NSConstantStringImpl__var_folders_5l_2l25j3tn0wl_3zy1hpsq1rhc0000gp_T_KDBlockTest_6946c5_mi_7);

 

2).執(zhí)行block
((void (*)(__block_impl *))((__block_impl *)testBlock)->FuncPtr)((__block_impl *)testBlock);

其實還是調用了block對象里的函數對象(_block_imp1)的函數指針(FuncPtr) 所指向的函數__main1_block_func_0,并把block自己作為參數傳遞進去。

static void __KDBlockTest__test3_block_func_0(struct __KDBlockTest__test3_block_impl_0 *__cself, int num) {  NSString *_person2 = __cself->_person2; // bound by copy  NSMutableArray *_listTest = __cself->_listTest; // bound by copy        NSLog((NSString *)&__NSConstantStringImpl__var_folders_5l_2l25j3tn0wl_3zy1hpsq1rhc0000gp_T_KDBlockTest_6946c5_mi_4,_person2,_person2);        NSLog((NSString *)&__NSConstantStringImpl__var_folders_5l_2l25j3tn0wl_3zy1hpsq1rhc0000gp_T_KDBlockTest_6946c5_mi_5,_listTest,_listTest);    }

 

總結:對于局部變量,變量不加__block修飾符,在block內部是無法修改變量的值。而且

  1. 對值類型的修改,如果block初始化后,無法同步到block內部
  2. 對于引用類型的修改,如果block初始化后,修改指針指向,即指向另外一塊內存,這樣也是無法同步到block內部
  3. 對于引用類型的修改,如果block初始化后,對指針指向的內存進行修改,即NSMutableArray add 、remove操作,這樣是可以用同步到block內部,但block內部同樣無法修改。

發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 仁怀市| 汝城县| 冷水江市| 高平市| 洮南市| 巴彦淖尔市| 阜康市| 阳春市| 礼泉县| 瑞安市| 十堰市| 江川县| 九龙坡区| 昭通市| 宁波市| 永顺县| 高尔夫| 福泉市| 东莞市| 和硕县| 淮南市| 三明市| 泸定县| 红桥区| 大化| 调兵山市| 宜章县| 阿克| 秦皇岛市| 广德县| 沙洋县| 门源| 大田县| 会理县| 扬中市| 石家庄市| 滁州市| 鹤峰县| 义马市| 鹤峰县| 桦甸市|