ARC - strong和weak指針

 

ARC指南1 - strong和weak指針

 

 

提示:本文中所說的"實例變量"便是"成員變量","局部變量"便是"本地變量"html

 

1、簡介java

ARC是自iOS 5以後增長的新特性,徹底消除了手動管理內存的煩瑣,編譯器會自動在適當的地方插入適當的retain、release、autorelease語句。你再也不須要擔憂內存管理,由於編譯器爲你處理了一切ios

注意:ARC 是編譯器特性,而不是 iOS 運行時特性(除了weak指針系統),它也不是垃圾收集器。所以 ARC 和手動內存管理性能是同樣的,有時還能更加快速,由於編譯器還能夠執行某些優化objective-c

 

2、原理app

ARC 的規則很是簡單:只要有變量指向對象,對象就會存在內存。當指針指向新值,或者指針再也不存在時,相關聯的對象就會自動釋放。這條規則對於實例變量、synthesize屬性、局部變量都是適用的ide

 

3、strong指針函數

控制器中有個文本輸入框框屬性工具

@property (nonatomic, assign) IBOutlet UITextField *nameField;  

 1.若是用戶在文本框中輸入mj這個字符串oop

那麼就能夠說,nameField的text屬性是NSString對象的指針,也就是擁有者,該對象保存了文本輸入框的內容post

 

2.若是執行了以下代碼

  1. NSString *name = self.nameField.text;  
一個對象能夠有多個擁有者,在上面代碼中,name變量一樣也是這個NSString對象的擁有者,也就是有兩個指針指向同一個對象

 

3.隨後用戶改變了輸入框的內容,好比

此時nameFeild的text屬性就指向了新的NSString對象。但原來的NSString對象仍然還有一個全部者(name變量),所以會繼續保留在內存中

 

4.當name變量得到新值,或者再也不存在時(如局部變量方法返回時、實例變量對象釋放時),原先的NSString對象就再也不擁有任何全部者,retain計數降爲0,這時對象會被釋放

如,給name變量賦予一個新值

  1. name = @"Jake";  

 

 

咱們稱name和nameField.text指針爲"Strong指針",由於它們可以保持對象的生命。默認全部實例變量和局部變量都是Strong指針

 

4、weak指針

weak型的指針變量仍然能夠指向一個對象,但不屬於對象的擁有者

1.執行下面的代碼

__weak NSString *name = self.nameField.text;  


 

name變量和nameField.text屬性都指向同一個NSString對象,但name不是擁有者

 

2.若是文本框的內容發生變化,則原先的NSString對象就沒有擁有者,會被釋放,此時name變量會自動變成nil,稱爲空指針

weak型的指針變量自動變爲nil是很是方便的,這樣阻止了weak指針繼續指向已釋放對象,避免了野指針的產生,否則會致使很是難於尋找的Bug,空指針消除了相似的問題

 

3.weak指針主要用於「父-子」關係,父親擁有一個兒子的strong指針,所以父親是兒子的全部者;但爲了阻止全部權循環,兒子須要使用weak指針指向父親。典型例子是delegate模式,你的ViewController經過strong指針(self.view)擁有一個UITableView, UITableView的dataSource和delegate都是weak指針,指向你的ViewController

 

5、strong和weak指針的使用注意

1.下面代碼是有問題的:

 

[java] view plaincopy
  1. __weak NSString *str = [[NSString alloc] initWithFormat:@"1234"];  
  2. NSLog(@"%@", str); // 打印出來是"(null)"  
str是個weak指針,因此NSString對象沒有擁有者,在建立以後就會被當即釋放。Xcode還會給出警告("Warning: Assigning retained object to weak variable; object will be released after assignment")

 

 

2.通常的指針變量默認就是strong類型的,所以通常咱們對於strong變量不加__strong修飾,如下兩行代碼是等價的:

[java] view plaincopy
  1. NSString *name = self.nameField.text;  
  2. __strong NSString *name = self.nameField.text;  

 

 

3.屬性能夠是strong或weak,寫法以下

 

[java] view plaincopy
  1. @property (nonatomic, strong) NSString *name;  
  2. @property (nonatomic, weak) id delegate;  

4.如下代碼在ARC以前是可能會行不通的,由於在手動內存管理中,從NSArray中移除一個對象時,這個對象會發送一條release消息,可能會被當即釋放。隨後NSLog()打印該對象就會致使應用崩潰

 

 

[java] view plaincopy
  1. id obj = [array objectAtIndex:0];  
  2. [array removeObjectAtIndex:0];  
  3. NSLog(@"%@", obj);  
在ARC中這段代碼是徹底合法的,由於obj變量是一個strong指針,它成爲了對象的擁有者,從NSArray中移除該對象也不會致使對象被釋放

 

 

6、ARC小結

1.有了ARC,咱們的代碼能夠清晰不少,你再也不須要考慮何時retain或release對象。惟一須要考慮的是對象之間的關聯,也就是哪一個對象擁有哪一個對象?

2.ARC也有一些限制:

1> 首先ARC只能工做於Objective-C對象,若是應用使用了Core Foundation或malloc()/free(),此時仍是須要你來手動管理內存

2> 此外ARC還有其它一些更爲嚴格的語言規則,以確保ARC可以正常地工做

3.雖然ARC管理了retain和release,但並不表示你徹底不須要關心內存管理的問題。由於strong指針會保持對象的生命,某些狀況下你仍然須要手動設置這些指針爲nil,不然可能致使應用內存不足。不管什麼時候你建立一個新對象時,都須要考慮誰擁有該對象,以及這個對象須要存活多久

4.ARC還能很好地結合C++使用,這對遊戲開發是很是有幫助的。對於iOS 4,ARC有一點點限制(不支持weak指針),但也沒太大關係

 

7、ARC使用注意總結

 

1.不能直接調用dealloc方法,不能調用retain,release,autorelease,retainCount方法,包括@selector(retain)的方式也不行
2.能夠用dealloc方法來管理一些資源,但不能用來釋放實例變量,也不能在dealloc方法裏面去掉[super dealloc]方法,在ARC下父類的dealloc一樣由編譯器來自動完成
3.Core Foundation類型的對象仍然能夠用CFRetain,CFRelease這些方法
4.不能再使用NSAllocateObject和NSDeallocateObject對象
5.不能在C結構體中使用對象指針,若是有相似功能能夠建立一個Objective-C類來管理這些對象
6.在id和void*之間沒有簡便的轉換方法,一樣在Objective-C和Core Foundation類型之間的轉換都須要使用編譯器制定的轉換函數
7.不能再使用NSAutoreleasePool對象,ARC提供了@autoreleasepool塊來代替它,這樣更有效率
8.不能使用內存存儲區(不能再使用NSZone)
9.不能以new爲開頭給一個屬性命名
10.聲明IBOutlet時通常應當使用weak,除了對StoryBoard這樣nib中間的頂層對象要用strong
11.weak至關於老版本的assign,strong至關於retain

 

 

ARC指南2 - ARC的開啓和禁止

分類: iOS基礎

要想將非ARC的代碼轉換爲ARC的代碼,大概有2種方式:

1.使用Xcode的自動轉換工具

2.手動設置某些文件支持ARC

 

1、Xcode的自動轉換工具

Xcode帶了一個自動轉換工具,能夠將舊的源代碼轉成ARC模式

1.ARC是LLVM 3.0編譯器的特性,而現有工程可能使用老的GCC 4.2或LLVM-GCC編譯器,所以首先須要設置使用LLVM 3.0編譯器:

(現使用的XCode4.5,LLVM 3.0已經升級到LLVM 4.1)

最好也選上Warnings中的Other Warning Flags 爲 -Wall,這樣編譯器就會檢查全部可能的警告,有助於咱們避免潛在的問題

 

2.Build Options下面的Run Static Analyzer選項也最好啓用,這樣每次Xcode編譯項目時,都會運行靜態代碼分析工具來檢查咱們的代碼

 

3.設置"Objective-C Automatic Reference Counting"選項爲YES,不過Xcode自動轉換工具會自動設置這個選項,這裏只是說明一下如何手動設置

 

4.打開Xcode的自動轉換工具

 

5.Xcode會顯示一個新窗口,讓你選擇哪些文件須要轉換

點擊Check按鈕,Xcode可能會彈出對話框提示項目不能轉換爲ARC,須要你準備好轉換(這裏暫時省略詳細說明)

 

6.若是沒有什麼警告、錯誤了,就會彈出一下提示窗口:

 

7.點擊Next,幾秒鐘後,Xcode會提示全部文件的轉換預覽,顯示源文件的全部改變。左邊是修改後的文件,右邊是原始文件。在這裏你能夠一個文件一個文件地查看Xcode的修改,以確保Xcode沒有改錯你的源文件:

點擊Save便可完成轉換

 

8.自動轉換以後,Xcode會移除全部retain、release、autorelease調用,這可能會致使代碼出現其它警告、無效語法等,這些都須要本身手工進行修改

注意:Xcode的自動轉換工具最好只使用一次,屢次使用可能會出現比較詭異的問題。假如你第一次轉換沒有轉換全部的文件,當你稍後試圖再次轉換剩餘的文件時,Xcode實際上不會執行任何轉換操做。所以最好一次就完成轉換,沒有轉換的文件能夠考慮手工進行修改

 

2、手動開啓某些文件的ARC

在Compiler Flags一列加上-fobjc-arc就表示開啓這個.m文件的ARC

 

3、禁止某些文件的ARC

在Compiler Flags一列加上-fno-objc-arc就表示禁止這個.m文件的ARC

 

 

 

ARC指南3 - @property

分類: iOS基礎

本章介紹引入ARC後@property的使用,跟ARC以前的仍是很不同的

 

1、.h和.m文件的變化說明

1.對於.h頭文件,主要是將屬性定義由retain變爲strong

 

[java] view plaincopy
  1. @property (retain, nonatomic)  
變爲

 

[java] view plaincopy
  1. @property (strong, nonatomic)  

2.在ARC以前,咱們常常在.m中使用分類拓展來增長私有的property

 

 

[java] view plaincopy
  1. @interface MJViewController ()  
  2. @property (nonatomic, retain) NSArray *data;  
  3. @end  
這樣作主要是簡化實例對象的手動內存管理,讓property的setter方法自動管理原來對象的釋放,以及新對象的retain。可是有了ARC,這樣的代碼就再也不須要了。通常來講,僅僅爲了簡化內存管理,是再也不須要使用property的,雖然你仍然能夠這樣作,但直接使用實例變量是更好的選擇。只有那些屬於public的實例變量,才應該定義爲property

 

咱們能夠直接在.m類實現中定義private實例變量,沒必要寫分類拓展了:

 

[java] view plaincopy
  1. @implementation MJViewController {  
  2.     NSArray *data;  
  3. }  
不過仍是要在viewDidUnload方法中將data設置爲nil,由於data是個strong指針,當再也不使用一個對象時,應該設置爲nil

 

[java] view plaincopy
  1. - (void)viewDidUnload {  
  2.     [super viewDidUnload];  
  3.     data = nil;  
  4. }  

2、IBOutlet

 

在ARC中,全部IBOutlet屬性都推薦使用weak, 這些view對象已經屬於View Controller的view hierarchy,不須要再次定義爲strong。所以,這些定義爲weak的IBOutlet屬性都不須要在IBOutlet中設置爲nil

 

3、@property的修飾符小結

• strong : 該屬性值對應 __strong 關鍵字,即該屬性所聲明的變量將成爲對象的持有者,等同於"retain"
• weak : 該屬性對應 __weak 關鍵字,與 __weak 定義的變量一致,該屬性所聲明的變量將沒有對象的全部權,而且當對象被釋放以後,對象將被自動賦值nil,記住IBOutlet應該使用weak
• unsafe_unretained : 等效於__unsafe_unretaind關鍵字聲明的變量,等同於以前的"assign",iOS 5以前的系統用該屬性代替 weak 來使用
• copy : 和以前的copy同樣,複製一個對象並建立strong關聯
• assign : 對象不能使用assign,但原始類型(BOOL、int、float)仍然可使用

 

 

 

ARC之strong,weak 解釋

 

先一句話總結:strong類保持他們擁有對象的活着,weak類他們擁有的對象被人家一牽就牽走,被人家一干就乾死。(strong是一個好大哥因此strong,呵呵,weak是一個虛大哥因此weak,呵呵)

 

好比有一個對象是string類,實例是@「hello」

現有兩個strong的string指針大哥a和b都指向了hello,如今b大哥把改爲了指向@「hi」。那麼這時候a大哥指向的值是什麼呢,答案仍是「hello」。而後,a大哥看hi不錯,也指向了hi,那麼如今hello就被都拋棄了,也就從內存中刪除了。由於a大哥是strong的,既是retain或者copy的,這兩個東西是可使對象保存在計算機內存裏的,因此若是即便b大哥拋棄hello,a大哥是有資本使@「hello」繼續活下去。

 

而如今又有兩個對象strong的c大哥和weak的d大哥,都指向hello,如今c大哥另有所愛,指向了以前的b大哥,同時a大哥也指向了b大哥,既如今沒有strong大哥指向hello。那麼如今這個weak的d大哥指向的對象就是一個屁啦,既nil。

 

strong和weak的區別
strong表示保留它指向的堆上的內存區域再也不指向這塊區域了。
也就是說我強力指向了一個區域,咱們再也不指向它的條件只有咱們指向nil或者我本身也不在內存上,沒有人strong指向我了,weak表示若是尚未人指向它了,它就會被清除內存,同時被指向nil,由於我不能讀取不存在的東西。
weak只在IOS5.0使用
這並非垃圾回收,咱們用reference count表示堆上還有多少strong指針,當它變爲0就立刻釋放。
 
 
 

iOS5 ARC,IBOutlets 應該定義strong仍是weak

  (2012-12-27 16:50:06)
標籤: 

objective-c

 

it

 
原帖:http://blog.csdn.net/yiyaaixuexi/article/details/7864974
 

寫這篇文章的原因,是由於我泡在stackoverflow上翻帖子,看到一個名爲Should IBOutlets be strong or weak under ARC? 的帖子很熱,而我對被採納爲標準答案的回答也有一些話要補充,我想對於每個初識ARC模式的人來講,都會有這個疑問,因此不妨我也來和你們探討一下。

 

有人問,在ARC下,IBOutlets到底應該定義成strong 仍是 weak ?支持這個答案的人最多,答案僅是摘自官方文檔的一個片斷:

 

From a practical perspective, in iOS and OS X outlets should be defined as declared properties. Outlets should generally be weak, except for those from File’s Owner to top-level objects in a nib file (or, in iOS, a storyboard scene) which should be strong. Outlets that you create will therefore typically be weak by default, because:

  • Outlets that you create to, for example, subviews of a view controller’s view or a window controller’s window, are arbitrary references between objects that do not imply ownership.

  • The strong outlets are frequently specified by framework classes (for example, UIViewController’s view outlet, or NSWindowController’s window outlet).

    
    @property (weak) IBOutlet MyView *viewContainerSubview; @property (strong) IBOutlet MyOtherClass *topLevelObject;

大意是說,在 ARC 中,通常outlet屬性都推薦使用 weak,應該使用 strong 的 outlet 是 File's Owner鏈接到 nib 的頂層對象。 

什麼是 File's Owner鏈接到 nib 的頂層對象呢?說白話一點,就是自定義的view,不是直接做爲main view裏面一個sub view直接顯示出來,而是須要經過實例化建立出來的。你本身實例化,固然須要strong了,否則誰還替你保留對象全部權呢?

 

以上的分析都沒有錯,可是總以爲少了點什麼。對於究竟是weak 仍是 strong,歸根結底,仍是要刨到對對象全部權的問題上,可是不便於總結出淺顯易懂的規律性使用法則。因而,就會有一個又一個的特例打破文檔所總結的常規,不明白規則的根是什麼,仍是會碰到麻煩的。

 

我來舉一個簡單的例子,建立一個程序入口指向navigation controller的工程,導航欄上拖2個按鈕:

右側按鈕用於控制相機按鈕的顯示與否,按照文檔的指示,咱們在程序中定義這兩個按鈕應爲weak屬性

 

  1. #import   
  2.   
  3. @interface TestViewController : UIViewController  
  4. {  
  5.     BOOL isShowing;  
  6. }  
  7.   
  8. @property (nonatomic,weak)IBOutlet UIBarButtonItem *controlBtn;  
  9. @property (nonatomic,weak)IBOutlet UIBarButtonItem *cameraBtn;  
  10.   
  11. -(IBAction)controlAction:(id)sender;  
  12. @end  


 

用右側按鈕,控制相機按鈕的隱藏和顯示:

 

  1. #import "TestViewController.h"  
  2.   
  3. @interface TestViewController ()  
  4.   
  5. @end  
  6.   
  7. @implementation TestViewController  
  8. @synthesize cameraBtn,controlBtn;  
  9.   
  10. - (void)viewDidLoad  
  11. {  
  12.     [super viewDidLoad];  
  13.     // Do any additional setup after loading the view, typically from a nib.  
  14.     isShowing = YES;  
  15. }  
  16.   
  17. - (void)viewDidUnload  
  18. {  
  19.     [super viewDidUnload];  
  20.     // Release any retained subviews of the main view.  
  21. }  
  22.   
  23. - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation  
  24. {  
  25.     return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);  
  26. }  
  27.   
  28. -(IBAction)controlAction:(id)sender  
  29. {  
  30.     if (isShowing) {  
  31.         self.controlBtn.title = @"顯示相機";  
  32.         self.navigationItem.leftBarButtonItem = nil;  
  33.         isShowing = NO;  
  34.     }else {  
  35.         self.controlBtn.title = @"隱藏相機";  
  36.         self.navigationItem.leftBarButtonItem = cameraBtn;  
  37.         isShowing = YES;  
  38.     }  
  39. }  
  40. @end  


 

實驗結果是,第一次隱藏了相機按鈕後,就再也顯示不出來了。緣由很簡單,cameraBtn指向了空,咱們丟失了cameraBtn的對象全部權。

解決問題的辦法有兩個:

1.不在xib或者storyboard上拖相機按鈕,而是用代碼建立,本身控制對象全部權

2.將 cameraBtn 定義爲strong

 

我想強調的固然是第二種方法,固然了,改爲strong後,相應的也須要配合ARC作下工做:

 

  1. - (void)viewDidUnload  
  2. {  
  3.     [super viewDidUnload];  
  4.     // Release any retained subviews of the main view.  
  5.     self.cameraBtn = nil;  
  6. }  

 

 

 

順便提一下ARC其餘屬性的規則:

 

  • strong:等同於"retain",屬性成爲對象的擁有者

  • weak:屬性是 weak pointer,當對象釋放時會自動設置爲 nil

  • unsafe_unretained:等同於以前的"assign",只有 iOS 4 才應該使用

  • copy:和以前的 copy 同樣,複製一個對象並建立 strong 關聯

  • assign:對象不能使用 assign,但原始類型(BOOL、int、float)仍然可使用 


 

最後一句,記憶規則,理解規則,善用規則。
相關文章
相關標籤/搜索