這段時間在研究關於ARC得循環引用致使變量不能釋放,在此先介紹一本書英文書:多線程
《Pro Multithreading and Memory Management for iOS and OS X with ARC, Grand Central Dispatch, and Blocks》app
(《iOS與OS X多線程和內存管理》)this
建議讀英文原版,中文版看的我稀裏糊塗的,後來被迫去看原版.這本書介紹了關於ARC的自動引用機制,這裏的機制相似:當C語言的局部變量離開他的做用域以後就會被清除,這裏的ARC也相似是這樣的原理,以下面的代碼同樣,當離開{}以後obj會被nil。默認id是強指針atom
{ /* * 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. */
不過有一種狀況會致使在{}內的變量再離開做用域以後不會釋放,這就是循環引用,下面我先貼一份沒有循環引用的代碼spa
//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. *code
* Leaving the scope of variable test1, its strong reference disappears.對象
* object B is released automatically.blog
*
* 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)