Objective-C對象的生命期取決于其引用的計數。在Objective-C的引用計數構架中,有一種特征叫做“自動釋放池塊”(autorelease pool)。釋放隊形有兩個方式:以后總是調用release方式,時期保留計數立即遞減:另一種是調用autorelease方法,將其加入”自動釋放池“時,系統會將其中多個對象發送release消息。
自動釋放池的原理.
存入到自動釋放池中的對象,在自動釋放池被銷毀的時候.會自動調用存儲在該自動釋放池中的所有對象的release方法.
可以解決的問題:
將創建的對象,存入到自動釋放池之中. 就不再需要手動的relase這個對象了.
因為池子銷毀的時候 就會自動的調用池中所有的對象的relase。
創建自動釋放池的語法運用如下:
@autoreleasepool {
//.......
}
如果在沒有創建自動釋放池的情況下給對象發送autorelease消息,那么控制臺就會輸出這樣一條消息:
Objective 0xabcd0123 of class __NSCFString autorelease
with no pool in place - just leaking - break on objc
autoreleaseNoPool() to doing
然而,一般情況下無需擔心自動釋放池的創建問題。Mac OS X 與iOS應用程序分別運用于Cocoa及Cocoa Touch環境中個。系統和會自動創建一些路線,比如說主線或者”大中樞派發“(Grand Central Dispatch,GCD)機制中的線程,這些線程默認都是自動釋放,每次執行”事件循環“時,就會進將其清空。因此,不需要自己來創建“自動釋放吃”同塵個只有一個地方需要創建自動釋放池,那就在main函數里。我們用自動釋放池來包裹應用程序的主入口。比方說。iOS程序的面函數經常這樣寫:
int main(int argh, char *argv[]) {
@autoreleasepool {
return UIApplicationMain(argh,argv,nil,@"EOCAppDelegate");
}
}
從技術角度來看,不是非得有個“自動釋放池”才行。應為塊的末尾敲好就是應用程序的終結處,二此時操作系統會把程序所占的全部內存全都釋放掉,雖然如此,但是如果不寫這個塊的話,那么有UIApplicationMain函數所自動釋放的那些對象,就沒有自動釋放池可以容納了,于是西戎會發出警告信息來表明這一情況。所以說,這個吃可以理解成最外圍捕捉自動釋放對象所用的池。
下面這段代碼中的話括號定義了自動化四方吃的范圍。自動釋放池于左括號處創建,并于對應右括號處清空。位于自動釋放池中的對象,將在此范圍末尾處收到release的消息。自動釋放吃可以嵌套。系統在自動該釋放對象的時候,會把它放到最內層的池里。比方說:
@autoreleasepool {
NSString *string = [NSString stringWithFormat:@"1 - %i",1];
@autoreleasepool {
NSNumber *number = [NSNumber numberWithInt:1];
}
}
使用注意
只有在自動釋放池中調用了對象的autorelease方法,這個對象才會被存儲到這個自動釋放池之中.
如果只是將對象的創建代碼寫在自動釋放之中,而沒有調用對象的autorelease方法.是不會將這個對象存儲到這個自動釋放池之中的.
對象的創建可以在自動釋放池的外面,在自動釋放池之中,調用對象的autorelease方法,就可以將這個對象存儲到這個自動釋放池之中.
如果對象的autorelease方法的調用放在自動釋放池的外面,是無法將其存儲的這個自動釋放池之中的.
autorelease 的調用只有放在自動釋放池之中 才可以講其存儲到自動釋放池之中, 對象的創建可以在外面
當自動釋放池結束的時候.僅僅是對存儲在自動釋放池中的對象發送1條release消息 而不是銷毀對象.
如果在自動釋放池中,調用同1個對象的autorelease方法多次.就會將對象存儲多次到自動釋放池之中.
在自動釋放池結束的時候.會為對象發送多條release消息.
所以,1個自動釋放池之中,只autorelease1次,只將這個對象放1次, 否則就會出現野指針錯誤.
如果在自動釋放池中,調用了存儲到自動釋放中的對象的release方法.
在自動釋放池結束的時候,還會再調用對象的release方法.
這個時候就有有可能會造成野指針操作.
將對象存儲到自動釋放池,并不會使對象的引用計數器+1 所以其好處就是:創建對象將對象存儲在自動釋放池,就不需要在寫個release了.
自動釋放池可以嵌套.
調用對象的autorelease方法,會講對象加入到當前自動釋放池之中
只有在當前自動釋放池結束的時候才會像對象發送release消息.
autorelease的應用場景.
創建對象,將對象存儲到自動釋放池之中. 就不需要再去手動的realse。
我們一般情況下,會為我們的類寫1個類方法,用來讓外界調用類方法來快速的得到1個對象.
規范:使用類方法得到的對象,要求這個對象就已經被autorelease過了.
提供1個類方法來快速的得到1個對象.
規范
這個類方法以類名開頭. 如果沒有參數就直接是類名 如果有參數就是 類名WithXX:
使用類方法得到的對象,要求這個對象就已經被autorelease過了.
- (instancetype)person
{
return [[[self alloc] init] autorelease];
}
以下是我整理的需要注意的事項:
(1)在自動釋放池@autoreleasepool{}中alloc一個對象后,仍然需要用[p1 autorelease];只是這個語句和[p1 release];不同,后者表示把p1的retainCount-1,而前者僅僅表示把p1放到自動釋放池中返回一個self,自動釋放池結束銷毀時,統一對里面的對象引用計數retainCount-1。
(2)@autoreleasepool{}可以隨意創建,也可以嵌套使用。
(3)不管這個對象是在自動釋放池內還是外創建的,只要在自動釋放池內寫一個[p1 autorelease];p1就會被放到自動釋放池中。注意autorelease是一個方法,且只有在自動釋放池中使用才有效。
(4)如果把一個對象重復加到自動釋放池如[p1 autorelease];[p1 autorelease];,那么會出錯。原因是:加載幾次,屆時自動釋放池就會用[p1 release];釋放幾次,但是由于這兩個加載的對象其實是一個對象同樣地址,所以第一次自動釋放正確,第二次自動釋放時發現已經被釋放了,所以p1就變成了野指針。
(5)以下是自動釋放池嵌套的使用規則和注意點。
[objc] view plain copy 在CODE上查看代碼片派生到我的代碼片
import <Foundation/Foundation.h>
import "Person.h"
int main(int argc, const charchar * argv[]) {
Person *p1=[[Person alloc]init];
@autoreleasepool {
@autoreleasepool {
[p1 autorelease];
}//在執行到此處時,p1被自動釋放
}
//以下代碼有錯誤
@autoreleasepool {
[p1 autorelease];//此時p1被加入進來
@autoreleasepool {
[p1 autorelease];//被重復加載進來,但仍然同一個
}//此處,p1被自動釋放了,所以第一次加進來的那個也被釋放了,因為是同一個對象
}//所以此處在調用[p1 release];時就出現報錯:野指針
return 0;
}
(6)@autoreleasepool的應用:如果需要在方法中創建對象,并把這個對象作為返回值,那么可以在這個方法中使用[*** autorelease];把它加入到自動釋放池中,否則,直接用[*** release];來匹配alloc的話,在該方法中就已經把這個對象alloc和release了一遍相當于釋放了,那么所謂的返回對象返回的時一個野指針(沒有指向任何對象)。當然,調用這個方法的代碼頁需要寫在自動釋放池作用域內才生效。
(7)接上面。返回對象的那個方法中,創建對象不建議直接用類名,而是用self,否則如果存在子類調用會崩潰。如Car *car1=[[self alloc]init];
(8)其實諸如NSString *str1=[NSString stringWithFormat:@"%@",@"hello"];也是調用了一個方法,并且返回了一個字符串對象。比照(6)和(7)我們得知這個stringWithFormat應該也是順便返回了一個autorelease。
(9)在ARC機制中,我們用@property聲明的成員變量,建議用strong代替之前手動管理內存時的retain,雖然后者仍然可以使用。因為我們在ARC中內存管理就是看是否有強指針指向對象,如有就不回收,如沒有就回收。所以強指針是strong,相反是weak。而基本數據類型我們還是習慣用assign。
(10)雖然Xcode提供了非ARC轉換成ARC的,很少有把整個非ARC轉換成ARC的。如果我們導入第三方庫時,需要非ARC和ARC共存,即我們系統默認是ARC,我們需要讓系統不要去管這個非ARC的第三方庫,如下設置:雙擊響應的.m文件,輸入-fno-objc-arc回車即可。
(11)順便,當出現兩個類循環引用的話(也就是A要包含B,B要包含A,即A對象要作為B的變量,B對象要作為A的變量),只需要把一方的strong改成weak,并且在響應的.h文件中把#import ".h"改成Class ***。如果因為改成Class ***而無法使用那個類的方法的話,只需要在它的.m文件中#import“.h”文件即可,這個因為不是在.h文件中導入所以不沖突。
這就是我整理的關于Autorelease的使用以及“自動釋放池塊”降低內存峰值的使用方法