zoukankan      html  css  js  c++  java
  • 浅谈 关于ARC循环引用得问题

    这段时间在研究关于ARC得循环引用导致变量不能释放,在此先介绍一本书英文书:

    《Pro Multithreading and Memory Management for iOS and OS X with ARC, Grand Central Dispatch, and Blocks》

    (《iOS与OS X多线程和内存管理》)

    建议读英文原版,中文版看的我稀里糊涂的,后来被迫去看原版.这本书介绍了关于ARC的自动引用机制,这里的机制类似:当C语言的局部变量离开他的作用域之后就会被清除,这里的ARC也类似是这样的原理,如下面的代码一样,当离开{}之后obj会被nil。默认id是强指针

    {
    /*
    * You create an object and have ownership. */
    id __strong obj = [[NSObject alloc] init];
    /*
    * The variable obj is qualified with __strong.
    * Which means, it has ownership of the object. */
    }
    /*
    * Leaving the scope of variable obj, its strong reference disappears.
    * The object is released automatically.
    * Because no one has ownership, the object is disposed of.
    */

    不过有一种情况会导致在{}内的变量再离开作用域之后不会释放,这就是循环引用,下面我先贴一份没有循环引用的代码

    //Test Class
    @interface Test : NSObject
    @property (nonatomic) id obj;
    - (void) setObj:(id)obj;
    @end
    @implementation Test
    - (void) setObj:(id)obj{
        _obj = obj;
    }
    @end
    
    //Use Test Class
    - (void)viewDidLoad
    {
        [super viewDidLoad];
        // Do any additional setup after loading the view, typically from a nib.
        id test0 = [[Test alloc]init];
        id test1 = [[Test alloc]init];
    
        self.t0 = test0;
        self.t1 = test1;
    }
    
    - (void) viewDidAppear:(BOOL)animated{
        [super viewDidAppear:animated];
    
        NSLog(@"test0 is %@",self.t0);
        NSLog(@"test1 is %@",self.t1);
        NSLog(@"test0 obj is %@",self.t0.obj);
        NSLog(@"test1 obj is %@",self.t1.obj);
        NSLog(@"viewDidApperar!");
    }
    /*  这里的输出结果:
    2014-11-18 11:39:31.654 circular[27065:60b] test0 is (null)
    2014-11-18 11:39:31.654 circular[27065:60b] test1 is (null)
    2014-11-18 11:39:31.655 circular[27065:60b] test0 obj is (null)
    2014-11-18 11:39:31.655 circular[27065:60b] test1 obj is (null)
    2014-11-18 11:39:31.655 circular[27065:60b] viewDidApperar!
        */

    /*

    • *  Leaving the scope of variable test0, its strong reference disappears.

    • *  object A is released automatically. *

    • *  Leaving the scope of variable test1, its strong reference disappears.

    • *  object B is released automatically.

      *

    • *  At this moment, obj_ of object B has a strong reference to object A. *

    • *  At this moment, obj_ of object A has a strong reference to object B. *

    • *  memory leaked!! */ 

     

    现在我贴一下存在循环引用的代码,这个时候局部变量的强指针相互引用,这里我们可以看见Test0的obj指向Test1,而Test1的obj指向Test0,导致释放不了.

    //Test Class
    @interface Test : NSObject
    @property (nonatomic) id obj;
    - (void) setObj:(id)obj;
    @end
    @implementation Test
    - (void) setObj:(id)obj{
        _obj = obj;
    }
    @end
    
    //Use Test Class
    - (void)viewDidLoad
    {
        [super viewDidLoad];
        // Do any additional setup after loading the view, typically from a nib.
        id test0 = [[Test alloc]init];
        id test1 = [[Test alloc]init];
        [test0 setObj:test1];
        [test1 setObj:test0];    
        self.t0 = test0;
        self.t1 = test1;
    }
    
    - (void) viewDidAppear:(BOOL)animated{
        [super viewDidAppear:animated];
    
        NSLog(@"test0 is %@",self.t0);
        NSLog(@"test1 is %@",self.t1);
        NSLog(@"test0 obj is %@",self.t0.obj);
        NSLog(@"test1 obj is %@",self.t1.obj);
        NSLog(@"viewDidApperar!");
    }
    
    /*这里的输出结果:
    2014-11-18 11:42:35.555 circular[27654:60b] test0 is <Test: 0x8c8fe20>
    2014-11-18 11:42:35.556 circular[27654:60b] test1 is <Test: 0x8cf7c20>
    2014-11-18 11:42:35.556 circular[27654:60b] test0 obj is <Test: 0x8cf7c20>
    2014-11-18 11:42:35.556 circular[27654:60b] test1 obj is <Test: 0x8c8fe20>
    2014-11-18 11:42:35.558 circular[27654:60b] viewDidApperar!
    */

     一般的解决办法就是weak obj,代码如下:

    //Test Class
    @interface Test : NSObject
    @property (nonatomic,weak) id obj;
    - (void) setObj:(id)obj;
    @end
    @implementation Test
    - (void) setObj:(id)obj{
        _obj = obj;
    }
    @end
    
    //Use Test Class
    - (void)viewDidLoad
    {
        [super viewDidLoad];
        // Do any additional setup after loading the view, typically from a nib.
        id test0 = [[Test alloc]init];
        id test1 = [[Test alloc]init];
        [test0 setObj:test1];
        [test1 setObj:test0];    
        self.t0 = test0;
        self.t1 = test1;
    }
    
    - (void) viewDidAppear:(BOOL)animated{
        [super viewDidAppear:animated];
    
        NSLog(@"test0 is %@",self.t0);
        NSLog(@"test1 is %@",self.t1);
        NSLog(@"test0 obj is %@",self.t0.obj);
        NSLog(@"test1 obj is %@",self.t1.obj);
        NSLog(@"viewDidApperar!");
    }
    
    /*这里的输出结果:
    2014-11-18 11:46:19.803 circular[28360:60b] test0 is (null)
    2014-11-18 11:46:19.804 circular[28360:60b] test1 is (null)
    2014-11-18 11:46:19.804 circular[28360:60b] test0 obj is (null)
    2014-11-18 11:46:19.805 circular[28360:60b] test1 obj is (null)
    2014-11-18 11:46:19.805 circular[28360:60b] viewDidApperar!
    */

    那么我们现在来了解一下为什么使用weak之后就会解除循环引用呢?

    当我们直接写  id __weak obj = [[NSObject alloc] init];  

    会提示警告:因为使用了weak,所以obj并不持有该对象,那么[[NSObject alloc] init]被创建之后没有人持有它,那么它就会被释放,所以这里应该修改成,当执行{}之后 obj0 和 obj1 都会被释放,因为当obj0被释放之后,obj1会变成nil因为weak引用不持有对象,当引用对象的强指针消失时,weak声明的指针也会自动null

    {
    /*
    * You create an object and have ownership. */
    id __strong obj0 = [[NSObject alloc] init];
    /*
    * The variable obj0 is qualified with __strong.
    * Which means, it has ownership of the object. */
    id __weak obj1 = obj0;
    /*
    * variable obj1 has a weak reference of the created object */
    } /*
    * Leaving the scope of variable obj0, its strong reference disappears.
    * The object is released automatically.
    * Because no one has ownership, the object is discarded. */

    那么下面这个例子就说明了weak会自动null

    id __weak obj1; //__strong ,__weak 声明的变量会自动设置成为nil,这里等同于 id __weak obj1 = nil; 
    {
    id __strong obj0 = [[NSObject alloc] init];
    obj1 = obj0;
    NSLog(@"A: %@", obj1); 
    } NSLog(
    @"B: %@", obj1); The result is: A: <NSObject: 0x753e180> B: (null)
  • 相关阅读:
    使用Hibernate实现简单的增、改、删、查操作
    Hibernate 配置
    Win7/8下Oracle的安装
    Android从相册获取图片
    Android图片缓存分析(一)
    TextView淡入淡出效果
    Android动画全解
    ListView的getChildAt(i)方法
    AIDL小记
    自定义SeekBar的Thumb不对齐的解决方法。
  • 原文地址:https://www.cnblogs.com/zuopeng/p/4105356.html
Copyright © 2011-2022 走看看