亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

block解析-內存

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

回顧

  1. 上一篇 我們了解到了用__block修飾的變量,可以在block內部修改,__block變量其實對應一個結構體
    struct __Block_byref__para1_0 {  void *__isa;__Block_byref__para1_0 *__forwarding; int __flags; int __size; char *_para1;};

    block結構體相應的也有一個成員引用,這樣會增加對局部變量的 _para1引用,在Block銷毀的時候引用就釋放掉了

    struct __main1_block_impl_0 {  struct __block_impl impl;  struct __main1_block_desc_0* Desc;  __Block_byref__para1_0 *_para1; // by ref}

     

     

  2. 上上上一篇 介紹了block內部 成員變量 使用,可以在block內部修改,對應一個、多個成員變量參數,block結構體內部有一個成員引用
    struct __KDBlockTest__test3_block_impl_0 {  struct __block_impl impl;  struct __KDBlockTest__test3_block_desc_0* Desc;  KDBlockTest *self;
    }

    這樣會增加對self的引用,在Block銷毀的時候引用就釋放掉了

循環引用

在使用的時候需要注意循環引用,即某個對象有一個copy或者strong的 block成員屬性,這時block內部直接引用了 成員變量(全局變量) 或者self,這樣就產生了self持有 block成員,block成員又持有了self,就會導致循環引用。

我們看以下代碼(ARC):

typedef void(^ActionTest)(void);@interface KDBlockTest(){    __block NSString *_person2;    ActionTest _action;}
@implementation KDBlockTest#PRagma mark - system-(instancetype)init{    self=[super init];    if(self)    {        [self test3];    }    return self;}-(void)dealloc{    NSLog(@"KDBlockTest dealloc");}#pragma mark - private////循環引用-(void )test3{    _person2=@"person2";    _action= ^(void) {        //block內賦值        NSLog(@"excuteing _person2:%@,%p",_person2,_person2);    };    _action();}

這樣我們執行以下代碼:

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

通過調試發現沒有走到dealloc,這里不管成員變量 _person2 是否聲明 __block都沒有什么影響。

成員變量 這一篇已經詳細介紹了,對于block 使用 成員變量、self來說,block內部是直接強引用self的。也就是block持有了self,在這里bock又作為self的一個成員被持有,所以就形成了相互引用,導致無法釋放。

__weak

對于上面這種情況,我們引入了__weak解決,__weak不會增加對象的引用計數,而且當指向的內存銷毀后,__weak指針會自動置為nil。

我們對上面的代碼稍作修改

-(void )test3{    __weak typeof(self) _weakSelf=self;    _person2=@"person2";    NSLog(@"init:%@,%p,%p",_person2,_person2,&self);    _action= ^(void) {        //block內賦值        NSLog(@"excuteing _person2:%@,%p,%p",_weakSelf.person2,_weakSelf.person2,&_weakSelf);    };    _action();}

輸出日志:

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

從日志可以看出block內部使用 person2 、_weakSelf 和外面的 person2 、self 地址是一樣的,看來也是引用關系,既達到block內部修改變量的效果,又沒有對變量產生強引用。我們來看下轉換后的代碼:

block結構體的定義:

struct __KDBlockTest__test3_block_impl_0 {  struct __block_impl impl;  struct __KDBlockTest__test3_block_desc_0* Desc;  __weak typeof (self) _weakSelf;  __KDBlockTest__test3_block_impl_0(void *fp, struct __KDBlockTest__test3_block_desc_0 *desc, __weak typeof (self) __weakSelf, int flags=0) : _weakSelf(__weakSelf) {    impl.isa = &_NSConcreteStackBlock;    impl.Flags = flags;    impl.FuncPtr = fp;    Desc = desc;  }};

重點就在這,使用_weak聲明的self,block結構體對應 也生成了一個_weak的self成員。我們在看下 我們的test3 方法:

static void _I_KDBlockTest_test3(KDBlockTest * self, SEL _cmd) {    __attribute__((objc_gc(weak))) typeof(self) _weakSelf=self;    (*(NSString **)((char *)self + OBJC_IVAR_$_KDBlockTest$_person2))=(NSString *)&__NSConstantStringImpl__var_folders_5l_2l25j3tn0wl_3zy1hpsq1rhc0000gp_T_KDBlockTest_d10f18_mi_1;    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);    (*(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);    ((void (*)(__block_impl *))((__block_impl *)(*(ActionTest *)((char *)self + OBJC_IVAR_$_KDBlockTest$_action)))->FuncPtr)((__block_impl *)(*(ActionTest *)((char *)self + OBJC_IVAR_$_KDBlockTest$_action)));}

block初始化的時候把  _weakSelf的地址傳入,block內部對_weakSelf進行弱引用。在執行block的時候

static void __KDBlockTest__test3_block_func_0(struct __KDBlockTest__test3_block_impl_0 *__cself) {  __weak typeof (self) _weakSelf = __cself->_weakSelf; // bound by copy        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);    }

通過取得block結構體的 弱引用對象self 成員來訪問相對應的方法 person2 (給對象發消息)。

 __weak 成員變量

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

-(void )test3{    _person2=@"person2";    __weak typeof(_person2) _weakPerson2=_person2;    NSLog(@"init:%@,%p,%p",_person2,_person2,&_person2);    NSLog(@"init weak:%@,%p,%p",_weakPerson2,_weakPerson2,&_weakPerson2);    _action= ^(void) {        //block內賦值
    //
_weakPerson2=@"person4";//error ,不能修改
        NSLog(@"excuteing _person2:%@,%p,%p",_weakPerson2,_weakPerson2,&_weakPerson2);    };    _person2=@"person22";    NSLog(@"before:%@,%p,%p",_person2,_person2,&_person2);    NSLog(@"before weak:%@,%p,%p",_weakPerson2,_weakPerson2,&_weakPerson2);    _action();    NSLog(@"after:%@,%p,%p",_person2,_person2,&_person2);}

輸出日志:

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

從日志可以看出:

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

我們來看下轉換后的代碼:其實和不加__block的局部變量差不多,無非多了一個弱引用,不會對引用計數有影響。

struct __KDBlockTest__test3_block_impl_0 {  struct __block_impl impl;  struct __KDBlockTest__test3_block_desc_0* Desc;  __weak typeof (self->_person2) _weakPerson2;  __KDBlockTest__test3_block_impl_0(void *fp, struct __KDBlockTest__test3_block_desc_0 *desc, __weak typeof (self->_person2) __weakPerson2, int flags=0) : _weakPerson2(__weakPerson2) {    impl.isa = &_NSConcreteStackBlock;    impl.Flags = flags;    impl.FuncPtr = fp;    Desc = desc;  }};
static void _I_KDBlockTest_test3(KDBlockTest * self, SEL _cmd) {    (*(NSString **)((char *)self + OBJC_IVAR_$_KDBlockTest$_person2))=(NSString *)&__NSConstantStringImpl__var_folders_5l_2l25j3tn0wl_3zy1hpsq1rhc0000gp_T_KDBlockTest_f32cef_mi_1;
//聲明_weak 變量 __attribute__((objc_gc(weak)))
typeof(_person2) _weakPerson2=(*(NSString **)((char *)self + OBJC_IVAR_$_KDBlockTest$_person2)); 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))); NSLog((NSString *)&__NSConstantStringImpl__var_folders_5l_2l25j3tn0wl_3zy1hpsq1rhc0000gp_T_KDBlockTest_f32cef_mi_3,_weakPerson2,_weakPerson2,&_weakPerson2);
//初始化block (
*(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); (*(NSString **)((char *)self + OBJC_IVAR_$_KDBlockTest$_person2))=(NSString *)&__NSConstantStringImpl__var_folders_5l_2l25j3tn0wl_3zy1hpsq1rhc0000gp_T_KDBlockTest_f32cef_mi_5; 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))); NSLog((NSString *)&__NSConstantStringImpl__var_folders_5l_2l25j3tn0wl_3zy1hpsq1rhc0000gp_T_KDBlockTest_f32cef_mi_7,_weakPerson2,_weakPerson2,&_weakPerson2); ((void (*)(__block_impl *))((__block_impl *)(*(ActionTest *)((char *)self + OBJC_IVAR_$_KDBlockTest$_action)))->FuncPtr)((__block_impl *)(*(ActionTest *)((char *)self + OBJC_IVAR_$_KDBlockTest$_action)));}

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

__weak typeof (self->_person2) _weakPerson2;

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

總結:

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

    •  

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

 


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
欧美中文字幕在线视频| 成人乱色短篇合集| 一区二区三区久久精品| 国外色69视频在线观看| 精品国产乱码久久久久久婷婷| 韩国国内大量揄拍精品视频| 国内精品美女av在线播放| 精品视频一区在线视频| 一区二区福利视频| 国产婷婷97碰碰久久人人蜜臀| 亚洲区一区二区| 精品在线小视频| 精品偷拍一区二区三区在线看| 亚洲激情自拍图| 奇米一区二区三区四区久久| 久久久免费观看视频| 亚洲人成在线观看网站高清| 亚洲国语精品自产拍在线观看| 国产97色在线| 国产精品爽黄69天堂a| 欧美性xxxx极品hd满灌| 成人黄色影片在线| 欧美精品久久一区二区| 不卡av电影院| 97人人爽人人喊人人模波多| 丝袜美腿亚洲一区二区| 欧美激情在线狂野欧美精品| 欧美视频中文字幕在线| 国产69精品99久久久久久宅男| 日本国产欧美一区二区三区| 欧美在线视频观看免费网站| 亚洲精品久久久久久久久久久久久| 欧美日韩一区免费| 26uuu久久噜噜噜噜| 中文字幕欧美日韩精品| 在线观看精品国产视频| 国产69精品99久久久久久宅男| 亚洲一区二区免费在线| 亚洲欧美日韩天堂一区二区| 55夜色66夜色国产精品视频| 亚洲第一天堂无码专区| 亚洲性生活视频在线观看| 精品国内产的精品视频在线观看| 亚洲最大av网站| 国产精品麻豆va在线播放| 亚洲精品色婷婷福利天堂| 欧美激情一区二区三区成人| 久久6免费高清热精品| 亚洲第一黄色网| 68精品国产免费久久久久久婷婷| 欧美麻豆久久久久久中文| 国产91精品视频在线观看| 成人免费看片视频| 欧美国产日本在线| 久久久久久国产三级电影| 国产精品99久久99久久久二8| 疯狂做受xxxx欧美肥白少妇| 国产一区二区三区在线免费观看| 欧美黑人xxxx| 91午夜理伦私人影院| 欧美午夜精品久久久久久人妖| 久久久精品网站| 88国产精品欧美一区二区三区| 亚洲福利精品在线| 欧美午夜视频一区二区| 久久精品国产亚洲精品| 欧美电影免费观看电视剧大全| 欧美激情网站在线观看| 欧美成人精品三级在线观看| 国产精品嫩草视频| 另类专区欧美制服同性| 国产精品久久久久久久久久99| 国产专区精品视频| 成人久久18免费网站图片| 国产一区二区动漫| 亚洲美女精品久久| 欧美高清性猛交| 国产高清视频一区三区| 成人综合国产精品| 亚洲男人天堂2024| 日韩在线一区二区三区免费视频| 91成人在线播放| 欧美日韩国产区| 国产精品久久久久av| 亚洲精品成人久久| 中文字幕在线成人| 亚洲一区二区三区乱码aⅴ| 亚洲精品日韩激情在线电影| 久久国产精品久久久久| 亚洲日韩中文字幕在线播放| 欧美日韩一二三四五区| 亚洲国产精品人久久电影| 成人黄色激情网| 欧美成人免费全部| 2025国产精品视频| 欧美成人高清视频| 97av在线播放| 亚洲欧美激情一区| 亚洲精品综合精品自拍| 国产91对白在线播放| 97免费视频在线播放| 日韩中文字幕在线看| 日韩精品免费在线视频| 亚洲区免费影片| 欧美精品www在线观看| 成人中文字幕+乱码+中文字幕| 国产一区二区三区在线视频| 久久精品成人一区二区三区| 亚洲福利视频久久| 亚洲一区二区三区乱码aⅴ蜜桃女| 精品久久久久久久久久久久久久| 国产区亚洲区欧美区| 亚洲综合精品伊人久久| 茄子视频成人在线| 欧美极品在线播放| 亚洲欧美在线x视频| 在线播放国产一区中文字幕剧情欧美| 日韩中文字幕亚洲| 韩国一区二区电影| 色偷偷噜噜噜亚洲男人| 成人免费观看网址| 欧洲亚洲在线视频| 国产亚洲一级高清| 精品小视频在线| 欧美成人一二三| 亚洲日本欧美中文幕| 欧美激情欧美狂野欧美精品| 久久久久久亚洲精品中文字幕| 8x拔播拔播x8国产精品| 一二美女精品欧洲| 亚洲第一视频网站| 欧美大码xxxx| 成人黄色中文字幕| 日韩在线视频导航| 国产精品久久久久久久久男| 91sa在线看| 欧美精品一区二区三区国产精品| 成人信息集中地欧美| 精品成人在线视频| 日韩免费看的电影电视剧大全| 91精品国产乱码久久久久久蜜臀| 亚洲国产一区二区三区四区| 国产精品午夜视频| 国产精品久久久久久久久久尿| 欧美大胆在线视频| 91精品久久久久久久久久久| 国产成人av在线播放| 久久人人爽人人爽爽久久| 在线丨暗呦小u女国产精品| 国产精品91免费在线| 亚洲欧美日韩在线高清直播| 91av在线国产| 久久久久久久爱| 国产噜噜噜噜噜久久久久久久久| 国产色视频一区| 久久影院模特热| 成人精品一区二区三区| 日韩av免费一区| 91夜夜未满十八勿入爽爽影院| 国产精品va在线| 91色p视频在线| 亚洲国产精品女人久久久| 欧美激情乱人伦一区| 亚洲黄色有码视频|