retain cycle 与block的正确调用

来源:互联网 发布:电脑硬件升级建议软件 编辑:程序博客网 时间:2024/04/28 02:00



ARC 环境下 


1 什么是retain cycle


1) 1…n 个对象,都能构成 retain cycle


假设关系都是 strong


A.a=A   一个对象retain cycle

A.b=B B.a=A 两个对象购成的cycle

A.b=B B.c=C C.d=D D.a=A 四个对象购成的环

推而广之 1…n 个对象,都能构成 retain cycle


2)如何解开retain cycle


 retain cycle是需要避免使用的,会造成理解的复杂性。但有时不得不使用。


 环生成后,也可解开

A.a=A---->A.a=nil;  A自动release了

A.b=B B.a=A----> A.b=nil(B release, A release) OR B.a=nil( A release, B release)

A.b=B B.c=C C.d=D D.a=A ----> 任设其中一个reference 为nil,整个环就断了,所有对象将release



3) retain cycle的生命期

  

   retain cycle的生命期 依赖于 strong reference的生命期。

   strong reference 的生命期就是该指针的生命期,如果 strong reference 是 object member, 那么 strong reference 的生命期就是 object 的生命期。(需要外界干涉破坏掉retain cycle)

   strong reference 也可以是 是在stack里,如在函数内。函数return时,reference 不得存在,object retain count 自动-1, retain cycle也不复存在了。(retain cycle会自动破坏掉)



4)在我们使用三方library  或open source时,如何以最安全的方式使用block,即便我们对该block不了解。



很多三方open source 我们很难知道他们内部怎么使用了block, 内部retain cycle又是怎么建立的。因为retain cycle生成可能有n个对象参与其中, 我们怎么才能以最安全的方式使用block?




确保使用 strong reference 只存在 stack即执行期中。__unsafe_unretained 或weak在block的生命期中。



(void)configPullToRefresh{

    __block __unsafe_unretained ICloud * tempSelf = self;

    [self.dataTableView addPullToRefreshWithActionHandler:^{

        __strong  ICloud * strongSelf = tempSelf;

        int64_t delayInSeconds = 2.0;

        dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);

        dispatch_after(popTime, dispatch_get_main_queue(), ^(void){

            [strongSelf refresh];

        });

    }];

}


分析



1.程序运行期, 进入configPullToRefresh 函数。生成 refreshWithActionHandler block, block 创建,block内将有一个__unsafe_unretained的 tempSelf成员。破保了在block的生命期内不会形成retain cycle.


2.当用户下拉刷新时,block 内调,进入block的执行期, 执行期用了__strong  TBSNSBasicView * strongSelf,将对 self 做一次retain, retain cycle出现了, 这时pop controller 也不会crashed,因为 block retain 了self 。block执行完,__strong  TBSNSBasicView * strongSelf走到了尽头, retain cycle 自动消息, self 自动release


3. 能用weak最好,__unsafe_unretained有些局限,须开发知道在进入block执行期时,该object 没dealloc,否则将crashed.但在我们的环境中,如果用户pop controller后,我们是不能 trigger  block 进入执行期的。



4.PLWeakCompatibility 提供了在5.0以前版本中 __weak的的适配可以了解能否在环境中使用。


https://github.com/plausiblelabs/PLWeakCompatibility




 

原创粉丝点击