提示:本文中所說的"實例變量"便是"成員變量","局部變量"便是"本地變量"html
1、簡介java
ARC是自iOS 5以後增長的新特性,徹底消除了手動管理內存的煩瑣,編譯器會自動在適當的地方插入適當的retain、release、autorelease語句。你再也不須要擔憂內存管理,由於編譯器爲你處理了一切ios
注意:ARC 是編譯器特性,而不是 iOS 運行時特性(除了weak指針系統),它也不是垃圾收集器。所以 ARC 和手動內存管理性能是同樣的,有時還能更加快速,由於編譯器還能夠執行某些優化objective-c
2、原理app
ARC 的規則很是簡單:只要有變量指向對象,對象就會存在內存。當指針指向新值,或者指針再也不存在時,相關聯的對象就會自動釋放。這條規則對於實例變量、synthesize屬性、局部變量都是適用的ide
3、strong指針函數
控制器中有個文本輸入框框屬性工具
1.若是用戶在文本框中輸入mj這個字符串oop
那麼就能夠說,nameField的text屬性是NSString對象的指針,也就是擁有者,該對象保存了文本輸入框的內容post
2.若是執行了以下代碼
3.隨後用戶改變了輸入框的內容,好比
此時nameFeild的text屬性就指向了新的NSString對象。但原來的NSString對象仍然還有一個全部者(name變量),所以會繼續保留在內存中
4.當name變量得到新值,或者再也不存在時(如局部變量方法返回時、實例變量對象釋放時),原先的NSString對象就再也不擁有任何全部者,retain計數降爲0,這時對象會被釋放
如,給name變量賦予一個新值
咱們稱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.下面代碼是有問題的:
2.通常的指針變量默認就是strong類型的,所以通常咱們對於strong變量不加__strong修飾,如下兩行代碼是等價的:
3.屬性能夠是strong或weak,寫法以下
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使用注意總結
要想將非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後@property的使用,跟ARC以前的仍是很不同的
1、.h和.m文件的變化說明
1.對於.h頭文件,主要是將屬性定義由retain變爲strong
咱們能夠直接在.m類實現中定義private實例變量,沒必要寫分類拓展了:
在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)仍然可使用
先一句話總結: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。
標籤: objective-cit |
寫這篇文章的原因,是由於我泡在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屬性
用右側按鈕,控制相機按鈕的隱藏和顯示:
實驗結果是,第一次隱藏了相機按鈕後,就再也顯示不出來了。緣由很簡單,cameraBtn指向了空,咱們丟失了cameraBtn的對象全部權。
解決問題的辦法有兩個:
1.不在xib或者storyboard上拖相機按鈕,而是用代碼建立,本身控制對象全部權
2.將 cameraBtn 定義爲strong
我想強調的固然是第二種方法,固然了,改爲strong後,相應的也須要配合ARC作下工做:
順便提一下ARC其餘屬性的規則:
strong:等同於"retain",屬性成爲對象的擁有者
weak:屬性是 weak pointer,當對象釋放時會自動設置爲 nil
unsafe_unretained:等同於以前的"assign",只有 iOS 4 才應該使用
copy:和以前的 copy 同樣,複製一個對象並建立 strong 關聯
assign:對象不能使用 assign,但原始類型(BOOL、int、float)仍然可使用
最後一句,記憶規則,理解規則,善用規則。