学习笔记-retain cycle

retain cycle产生情况

A和B两个对象,A持有B,B同时也持有A,A只有B释放之后才有可能释放,同样B只有A释放后才可能释放,当双方都在等待对方释放的时候, retain cycle就形成了,结果是,两个对象都永远不会被释放,最终内存泄露。

retain cycle的避免

一般情况下,防止出现retain cycle有两个方法:

  • 保持子对象引用父对象时是若引用
  • 将造成retain cycle的一个变量置为nil,break掉环即可

需要特别小心的是,在使用block时,block引用的变量会自动retain一次,来保证block的调用是有效的,但同时这种retain是隐式的,block本身又可以看做一个对象,也存在生命周期,也可以被持有,所以极易造成retain cycle。
比如:

Car *car = [[Car alloc]init];
    car.name = ^{
        [car Run];
        [car release];// ARC中不需要release
    };

分析以上代码:car与block互相持有,造成retain cycle。为了解除retain cycle可以做出如下修改:

    Car *car = [[Car alloc]init];
    car.name = ^{
        [car run];
        car.name = nil;
        [car release];// ARC中不需要release
    };

分析以上代码:car.name=nil,不会造成retain cycle。


由于在ARC中引入了* __block、__unsafe_unretained、__weak*、__strong用于修饰变量,注:

  • __strong:赋值给这个变量的对象会自动被retain一次,如果在block中引用它,block也会retain它一次。
  • __weak:类似于__unsafe_unretained,只是如果所持有的对象被释放后,变量会自动被设置为nil,不会被block retain,更为安全
  • __block:变量能在block中被修改(值修改,而不是修改对象中的某一个属性,可以理解为修改指针的指向),会被自动retain。
  • __unsafe_unretained:赋值给这个变量不会被retain,被他修饰的变量的存在但不能保证持有对象的可靠性,它可能已经被释放了,而且留下了一个不安全的指针。
    上面产生retain cycle的代码也可修改为以下形式:
__block Car *car = [[Car alloc]init];
    car.name = ^{
        [car run];
        car = nil;
    };
Car *car = [[Car alloc]init];
   __weak __typeof (car) weakcar = car;
   car.name = ^{
       __typeof (car) strongcar = weakcar;
       [strongcar run];
   };

以上是个人理解,如有不对的地方,请指出。

你可能感兴趣的:(学习笔记-retain cycle)