自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

block 解析 - 內(nèi)存

移動(dòng)開發(fā) iOS
block結(jié)構(gòu)體相應(yīng)的也有一個(gè)成員引用,這樣會(huì)增加對(duì)局部變量的 _para1引用,在Block銷毀的時(shí)候引用就釋放掉了

我們了解到了用__block修飾的變量,可以在block內(nèi)部修改,__block變量其實(shí)對(duì)應(yīng)一個(gè)結(jié)構(gòu)體

  1. struct __Block_byref__para1_0 { 
  2.   void *__isa; 
  3. __Block_byref__para1_0 *__forwarding; 
  4.  int __flags; 
  5.  int __size; 
  6.  char *_para1; 
  7. }; 

block結(jié)構(gòu)體相應(yīng)的也有一個(gè)成員引用,這樣會(huì)增加對(duì)局部變量的 _para1引用,在Block銷毀的時(shí)候引用就釋放掉了

  1. struct __main1_block_impl_0 { 
  2.   struct __block_impl impl; 
  3.   struct __main1_block_desc_0* Desc; 
  4.   __Block_byref__para1_0 *_para1; // by ref 

block內(nèi)部 成員變量 使用,可以在block內(nèi)部修改,對(duì)應(yīng)一個(gè)、多個(gè)成員變量參數(shù),block結(jié)構(gòu)體內(nèi)部有一個(gè)成員引用

  1. struct __KDBlockTest__test3_block_impl_0 { 
  2.   struct __block_impl impl; 
  3.   struct __KDBlockTest__test3_block_desc_0* Desc; 
  4.   KDBlockTest *self; 

這樣會(huì)增加對(duì)self的引用,在Block銷毀的時(shí)候引用就釋放掉了

循環(huán)引用

在使用的時(shí)候需要注意循環(huán)引用,即某個(gè)對(duì)象有一個(gè)copy或者strong的 block成員屬性,這時(shí)block內(nèi)部直接引用了 成員變量(全局變量) 或者self,這樣就產(chǎn)生了self持有 block成員,block成員又持有了self,就會(huì)導(dǎo)致循環(huán)引用。

我們看以下代碼(ARC):

  1. typedef void(^ActionTest)(void); 
  2. @interface KDBlockTest() 
  3.     __block NSString *_person2; 
  4.     ActionTest _action; 
  5. }
  1. @implementation KDBlockTest 
  2. #pragma mark - system 
  3. -(instancetype)init 
  4.     self=[super init]; 
  5.     if(self) 
  6.     { 
  7.         [self test3]; 
  8.     } 
  9.     return self; 
  10. -(void)dealloc 
  11.     NSLog(@"KDBlockTest dealloc"); 
  12.  
  13. #pragma mark - private 
  14. ////循環(huán)引用 
  15. -(void )test3 
  16.     _person2=@"person2"
  17.     _action= ^(void) { 
  18.         //block內(nèi)賦值 
  19.         NSLog(@"excuteing _person2:%@,%p",_person2,_person2); 
  20.     }; 
  21.     _action(); 

這樣我們執(zhí)行以下代碼:

  1. KDBlockTest *_test=[[KDBlockTest alloc]init]; 

通過調(diào)試發(fā)現(xiàn)沒有走到dealloc,這里不管成員變量 _person2 是否聲明 __block都沒有什么影響。

成員變量 這一篇已經(jīng)詳細(xì)介紹了,對(duì)于block 使用 成員變量、self來說,block內(nèi)部是直接強(qiáng)引用self的。也就是block持有了self,在這里bock又作為self的一個(gè)成員被持有,所以就形成了相互引用,導(dǎo)致無法釋放。

——weak

對(duì)于上面這種情況,我們引入了__weak解決,__weak不會(huì)增加對(duì)象的引用計(jì)數(shù),而且當(dāng)指向的內(nèi)存銷毀后,__weak指針會(huì)自動(dòng)置為nil。

我們對(duì)上面的代碼稍作修改

 

  1. -(void )test3 
  2.     __weak typeof(self) _weakSelf=self; 
  3.     _person2=@"person2"
  4.     NSLog(@"init:%@,%p,%p",_person2,_person2,&self); 
  5.     _action= ^(void) { 
  6.         //block內(nèi)賦值 
  7.         NSLog(@"excuteing _person2:%@,%p,%p",_weakSelf.person2,_weakSelf.person2,&_weakSelf); 
  8.     }; 
  9.     _action(); 

輸出日志:

2014-07-29 13:38:30.872 Test[2642:60b] init:person2,0x5b980,0x27dae944
2014-07-29 13:38:30.875 Test[2642:60b] excuteing _person2:person2,0x5b980,0x1562ed44
2014-07-29 13:38:30.876 Test[2642:60b] KDBlockTest dealloc

從日志可以看出block內(nèi)部使用 person2 、_weakSelf 和外面的 person2 、self 地址是一樣的,看來也是引用關(guān)系,既達(dá)到block內(nèi)部修改變量的效果,又沒有對(duì)變量產(chǎn)生強(qiáng)引用。我們來看下轉(zhuǎn)換后的代碼:

block結(jié)構(gòu)體的定義:

  1. struct __KDBlockTest__test3_block_impl_0 { 
  2.   struct __block_impl impl; 
  3.   struct __KDBlockTest__test3_block_desc_0* Desc; 
  4.   __weak typeof (self) _weakSelf; 
  5.   __KDBlockTest__test3_block_impl_0(void *fp, struct __KDBlockTest__test3_block_desc_0 *desc, __weak typeof (self) __weakSelf, int flags=0) : _weakSelf(__weakSelf) { 
  6.     impl.isa = &_NSConcreteStackBlock; 
  7.     impl.Flags = flags; 
  8.     impl.FuncPtr = fp; 
  9.     Desc = desc; 
  10.   } 
  11. }; 

重點(diǎn)就在這,使用_weak聲明的self,block結(jié)構(gòu)體對(duì)應(yīng) 也生成了一個(gè)_weak的self成員。我們?cè)诳聪?我們的test3 方法:

  1. static void _I_KDBlockTest_test3(KDBlockTest * self, SEL _cmd) { 
  2.     __attribute__((objc_gc(weak))) typeof(self) _weakSelf=self; 
  3.     (*(NSString **)((char *)self + OBJC_IVAR_$_KDBlockTest$_person2))=(NSString *)&__NSConstantStringImpl__var_folders_5l_2l25j3tn0wl_3zy1hpsq1rhc0000gp_T_KDBlockTest_d10f18_mi_1; 
  4.     NSLog((NSString *)&__NSConstantStringImpl__var_folders_5l_2l25j3tn0wl_3zy1hpsq1rhc0000gp_T_KDBlockTest_d10f18_mi_2,(*(NSString **)((char *)self + OBJC_IVAR_$_KDBlockTest$_person2)),(*(NSString **)((char *)self + OBJC_IVAR_$_KDBlockTest$_person2)),&self); 
  5.     (*(ActionTest *)((char *)self + OBJC_IVAR_$_KDBlockTest$_action))= (void (*)())&__KDBlockTest__test3_block_impl_0((void *)__KDBlockTest__test3_block_func_0, &__KDBlockTest__test3_block_desc_0_DATA, _weakSelf, 570425344); 
  6.     ((void (*)(__block_impl *))((__block_impl *)(*(ActionTest *)((char *)self + OBJC_IVAR_$_KDBlockTest$_action)))->FuncPtr)((__block_impl *)(*(ActionTest *)((char *)self + OBJC_IVAR_$_KDBlockTest$_action))); 

block初始化的時(shí)候把  _weakSelf的地址傳入,block內(nèi)部對(duì)_weakSelf進(jìn)行弱引用。在執(zhí)行block的時(shí)候

  1. static void __KDBlockTest__test3_block_func_0(struct __KDBlockTest__test3_block_impl_0 *__cself) { 
  2.   __weak typeof (self) _weakSelf = __cself->_weakSelf; // bound by copy 
  3.  
  4.  
  5.         NSLog((NSString *)&__NSConstantStringImpl__var_folders_5l_2l25j3tn0wl_3zy1hpsq1rhc0000gp_T_KDBlockTest_d10f18_mi_3,((NSString *(*)(id, SEL))(void *)objc_msgSend)((id)_weakSelf, sel_registerName("person2")),((NSString *(*)(id, SEL))(void *)objc_msgSend)((id)_weakSelf, sel_registerName("person2")),&_weakSelf); 
  6.     } 

通過取得block結(jié)構(gòu)體的 弱引用對(duì)象self 成員來訪問相對(duì)應(yīng)的方法 person2 (給對(duì)象發(fā)消息)。

—weak變量

上面例子,我們稍作修改:

  1. (void )test3 
  2.     _person2=@"person2"
  3.     __weak typeof(_person2) _weakPerson2=_person2; 
  4.     NSLog(@"init:%@,%p,%p",_person2,_person2,&_person2); 
  5.     NSLog(@"init weak:%@,%p,%p",_weakPerson2,_weakPerson2,&_weakPerson2); 
  6.     _action= ^(void) { 
  7.         //block內(nèi)賦值 
  8.     //_weakPerson2=@"person4";//error ,不能修改 
  9.  
  10.         NSLog(@"excuteing _person2:%@,%p,%p",_weakPerson2,_weakPerson2,&_weakPerson2); 
  11.     }; 
  12.     _person2=@"person22"
  13.     NSLog(@"before:%@,%p,%p",_person2,_person2,&_person2); 
  14.     NSLog(@"before weak:%@,%p,%p",_weakPerson2,_weakPerson2,&_weakPerson2); 
  15.     _action(); 
  16.     NSLog(@"after:%@,%p,%p",_person2,_person2,&_person2); 

輸出日志:

2014-07-29 15:29:33.472 Test[2719:60b] init:person2,0x5397c,0x16566db8
2014-07-29 15:29:33.475 Test[2719:60b] init weak:person2,0x5397c,0x27db693c
2014-07-29 15:29:33.476 Test[2719:60b] before:person22,0x539bc,0x16566db8
2014-07-29 15:29:33.477 Test[2719:60b] before weak:person2,0x5397c,0x27db693c
2014-07-29 15:29:33.479 Test[2719:60b] excuteing _person2:person2,0x5397c,0x165b5be4
2014-07-29 15:29:33.480 Test[2719:60b] after:person22,0x539bc,0x16566db8
2014-07-29 15:29:33.481 Test[2719:60b] KDBlockTest dealloc

從日志可以看出:

  1. 直接用__weak修飾符修飾_person2變量也可以,也可以避免循環(huán)引用,但是不可以在block內(nèi)部修改外部 參數(shù)的值
  2. 在block外部修改變量指針指向,即把指針指向另外一塊內(nèi)存,block內(nèi)部無法更新到。

我們來看下轉(zhuǎn)換后的代碼:其實(shí)和不加__block的局部變量差不多,無非多了一個(gè)弱引用,不會(huì)對(duì)引用計(jì)數(shù)有影響。

 

  1. struct __KDBlockTest__test3_block_impl_0 { 
  2.   struct __block_impl impl; 
  3.   struct __KDBlockTest__test3_block_desc_0* Desc; 
  4.   __weak typeof (self->_person2) _weakPerson2; 
  5.   __KDBlockTest__test3_block_impl_0(void *fp, struct __KDBlockTest__test3_block_desc_0 *desc, __weak typeof (self->_person2) __weakPerson2, int flags=0) : _weakPerson2(__weakPerson2) { 
  6.     impl.isa = &_NSConcreteStackBlock; 
  7.     impl.Flags = flags; 
  8.     impl.FuncPtr = fp; 
  9.     Desc = desc; 
  10.   } 
  11. }; 
  1. static void _I_KDBlockTest_test3(KDBlockTest * self, SEL _cmd) { 
  2.  
  3.     (*(NSString **)((char *)self + OBJC_IVAR_$_KDBlockTest$_person2))=(NSString *)&__NSConstantStringImpl__var_folders_5l_2l25j3tn0wl_3zy1hpsq1rhc0000gp_T_KDBlockTest_f32cef_mi_1; 
  4. //聲明_weak 變量 
  5.     __attribute__((objc_gc(weak))) typeof(_person2) _weakPerson2=(*(NSString **)((char *)self + OBJC_IVAR_$_KDBlockTest$_person2)); 
  6.     NSLog((NSString *)&__NSConstantStringImpl__var_folders_5l_2l25j3tn0wl_3zy1hpsq1rhc0000gp_T_KDBlockTest_f32cef_mi_2,(*(NSString **)((char *)self + OBJC_IVAR_$_KDBlockTest$_person2)),(*(NSString **)((char *)self + OBJC_IVAR_$_KDBlockTest$_person2)),&(*(NSString **)((char *)self + OBJC_IVAR_$_KDBlockTest$_person2))); 
  7.     NSLog((NSString *)&__NSConstantStringImpl__var_folders_5l_2l25j3tn0wl_3zy1hpsq1rhc0000gp_T_KDBlockTest_f32cef_mi_3,_weakPerson2,_weakPerson2,&_weakPerson2); 
  8. //初始化block 
  9.     (*(ActionTest *)((char *)self + OBJC_IVAR_$_KDBlockTest$_action))= (void (*)())&__KDBlockTest__test3_block_impl_0((void *)__KDBlockTest__test3_block_func_0, &__KDBlockTest__test3_block_desc_0_DATA, _weakPerson2, 570425344); 
  10.     (*(NSString **)((char *)self + OBJC_IVAR_$_KDBlockTest$_person2))=(NSString *)&__NSConstantStringImpl__var_folders_5l_2l25j3tn0wl_3zy1hpsq1rhc0000gp_T_KDBlockTest_f32cef_mi_5; 
  11.     NSLog((NSString *)&__NSConstantStringImpl__var_folders_5l_2l25j3tn0wl_3zy1hpsq1rhc0000gp_T_KDBlockTest_f32cef_mi_6,(*(NSString **)((char *)self + OBJC_IVAR_$_KDBlockTest$_person2)),(*(NSString **)((char *)self + OBJC_IVAR_$_KDBlockTest$_person2)),&(*(NSString **)((char *)self + OBJC_IVAR_$_KDBlockTest$_person2))); 
  12.     NSLog((NSString *)&__NSConstantStringImpl__var_folders_5l_2l25j3tn0wl_3zy1hpsq1rhc0000gp_T_KDBlockTest_f32cef_mi_7,_weakPerson2,_weakPerson2,&_weakPerson2); 
  13.     ((void (*)(__block_impl *))((__block_impl *)(*(ActionTest *)((char *)self + OBJC_IVAR_$_KDBlockTest$_action)))->FuncPtr)((__block_impl *)(*(ActionTest *)((char *)self + OBJC_IVAR_$_KDBlockTest$_action))); 

在聲明 _weak變量的時(shí)候,生成了一個(gè) 弱引用的指針 指向 self的person2變量。在block初始化的時(shí)候,把弱引用指針指向的內(nèi)容地址 傳遞給了block成員

__weak typeof (self->_person2) _weakPerson2;

block結(jié)構(gòu)體內(nèi)部通過 成員 _weakPerson2 直接弱引用了外部變量 person2的內(nèi)容地址。這時(shí)候如果把person2指針指向另外一塊內(nèi)存地址,那么肯定是同步不到block內(nèi)部的,這個(gè)和 局部變量  大同小異。

總結(jié):

  1. 聲明 __weak typeof(self) _weakSelf=self;  這樣block內(nèi)部 生成一個(gè)成員 ,會(huì)對(duì)self弱引用,對(duì)于值類型、引用類型都可以修改,并且修改指針指向都可以同步到任何地方。
  2. 聲明 __weak typeof(_person2) _weakPerson2=_person2;  針對(duì)某個(gè)具體的成員變量使用weak修飾符,這樣可以避免循環(huán)引用,并且不能再block內(nèi)部修改_weakPerson2。規(guī)則如下:
    • 對(duì)值類型的修改,如果block初始化后,對(duì)值類型修改,無法同步到block內(nèi)部。
    • 對(duì)于引用類型的修改,如果block初始化后,修改指針指向,即指向另外一塊內(nèi)存,這樣也是無法同步到block內(nèi)部

       

      對(duì)于引用類型的修改,如果block初始化后,對(duì)指針指向的內(nèi)存進(jìn)行修改,即NSMutableArray add 、remove操作,這樣是可以用同步到block內(nèi)部。

責(zé)任編輯:chenqingxiang 來源: cnblogs
相關(guān)推薦

2014-07-31 16:47:10

block

2013-07-19 13:16:26

iOS中BlockiOS開發(fā)學(xué)習(xí)內(nèi)存管理

2015-03-30 11:18:50

內(nèi)存管理Android

2010-09-25 14:12:50

Java內(nèi)存分配

2010-09-16 09:13:09

CSS display

2016-03-21 10:31:25

Android內(nèi)存泄露

2010-09-26 14:55:46

JVM內(nèi)存監(jiān)控

2017-03-07 09:45:43

iOSBlock開發(fā)

2010-09-25 12:54:24

JVM內(nèi)存

2020-12-23 13:14:00

LinuxLinux內(nèi)存Swap

2021-10-15 08:51:09

Linux內(nèi)存 Kmalloc

2013-10-11 17:24:47

Linux運(yùn)維內(nèi)存管理

2021-03-30 10:50:18

Linux內(nèi)存命令

2021-04-30 20:20:36

HugePages大內(nèi)存頁系統(tǒng)

2016-10-09 14:41:40

Swift開發(fā)ARC

2016-03-07 09:09:35

blockios開發(fā)實(shí)踐

2013-07-19 12:52:50

iOS中BlockiOS開發(fā)學(xué)習(xí)

2010-02-22 08:58:35

JVM內(nèi)存模型垃圾收集

2011-05-05 18:28:18

2023-10-12 19:41:55

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)