羅裏吧嗦顛三倒四,單純的我的筆記。html
引用計數上一篇已經有大概講過。在Objective-C裏,每一個繼承自NSObject的對象都會記錄自身的引用計數,一番加加減減以後,變成0就會釋放掉。
MRC是Mannul Reference Counting的縮寫,意思也很簡單,這番加加減減都靠手動管理的意思。segmentfault
使用時的基本原則是:管好本身。每一個對象,引用別的對象時加了幾回計數最終到了不用的時候就要減幾回。不能多也不能少。
這樣就聚焦了不少。框架
致使引用計數增長的操做,顯式的retain很少說,剩下的就是四個關鍵字:alloc、new(以及new開頭的方法)、copy、mutableCopy,使用這四個關鍵字獲得的對象,就算你本身加的引用計數,回頭要本身減掉。函數
引用計數減小的操做就是release了。oop
AutoReleasePool是個自動釋放池,加入其中的對象會延遲到Pool「結束」時釋放。
在MRC中,你能夠顯式建立一個NSAutoReleasePool,顯式地將一個對象加入進去,並顯式釋放AutoReleasePool:this
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; // Code benefitting from a local autorelease pool. NSObject *obj = [[[NSObject alloc] init] autorelease]; [pool release];//[pool drain];
在ARC中,須要經過特殊的語法:code
@autoreleasepool { // Code benefitting from a local autorelease pool. }
默認地,每一個Runloop迭代開始時會建立一個AutoReleasePool,Runloop迭代結束時釋放。也就是說,當咱們沒有顯式建立AutoReleasePool時,autorelease的對象會在Runloop迭代結束時釋放。
當咱們顯式地建立AutoReleasePool時,其釋放時機是咱們決定的(顯式調用release/drain或block結束)。orm
主動使用AutoReleasePool的目的一般是爲了控制內存峯值。好比,我有一個大循環,每次循環都會建立比較大的autorelease的臨時對象。若是不顯式釋放,這些臨時對象會在整個循環結束後才一塊兒釋放,期間可能形成內存佔用太高。這種狀況下就能夠在每次循環內聲明autoreleasepool,保證臨時對象不會堆積。htm
ARC爲咱們自動地作了不少,屏蔽了不少細節,理論上來講,咱們只須要關注對象間的全部權關係便可。
上層機制雖然簡單,涉及到的細節仍是有不少的,可喜可賀的是,ARC是有標準文檔的。簡直...對象
ARC提供的變量修飾符有如下幾個:
提供的屬性修飾符有:
(基本類型默認是assign,對象類型默認是strong)
強引用,很少說了。注意聲明變量和屬性時若未加說明,默認是強引用。
弱引用。當對象被釋放時,weak修飾的變量會被置爲nil。
仔細想一想,想要實現這個特性,全部的weak變量都須要放到一個全局的map裏,實現成本仍是比較高的。
不作任何額外操做。
__autoreleasing標記的變量等價於調用autorelease方法
想到一個小問題:對於函數返回值,ARC是怎麼知道要不要加引用計數呢?
看這幾行代碼:
- (void)testMethod { NSObject *obj = [NSObject new]; NSArray *array = [NSArray array]; // do something }
在ARC中,obj和array用完以後都會被自動釋放,可是細想之下其實有很多細節。
要知道,[NSObject new]返回的對象引用計數是有+1的,而[NSArray array]並非。
這倆玩意兒引用計數差了1,ARC是怎麼知道誰要多釋放一次的?
在MRC中,咱們知道new出來的obj須要手動釋放,而array就不須要,是經過方法的關鍵詞進行判斷。
可是方法中的關鍵詞不該該是某種約定嗎?ARC難道也會去看一個方法是不是以new開頭?
看了文檔以後發現...ARC還真是這麼作的...
Methods in the alloc, copy, init, mutableCopy, and new families are implicitly marked __attribute__((ns_returns_retained)).
回想起來,在MRC時代,這些關鍵詞應該是止步於約定的。而ARC或許是爲了平滑過渡,把曾經的約定變成了語法規範,emmm,感受這麼搞不是很好啊。
在ARC以後,內存管理的問題減小了不少,但仍然有一些遺留。其中最重要的一部分就是Block相關的內存管理。
參考Objective-C中Block的循環引用問題
Core Foundation框架 (CoreFoundation.framework) 是一組C語言接口,它們爲iOS應用程序提供基本數據管理和服務功能。
Objective-C對象和CF對象是能夠直接轉換的:
CFStringRef aCFString = (CFStringRef)aNSString; NSString *aNSString = (NSString *)aCFString;
然而ARC是不支持CF對象的內存管理的,這就須要咱們關注誰來釋放轉換後的對象的問題。
在MRC中,相對來講比較簡單,CFRelease和release方法是等效的,擇機使用便可。
這裏主要關注ARC下的狀況。
根據不一樣需求,有3種轉換方式
__bridge不改變對象全部權。
NSString *aNSString = [[NSString alloc]initWithFormat:@"test"]; CFStringRef aCFString = (__bridge CFStringRef)aNSString; // do something
CFStringRef aCFString = CFStringCreateWithCString(NULL, "test", kCFStringEncodingASCII); NSString *aNSString = (__bridge NSString *)aCFString; // do something CFRelease(aCFString);
全部權給CF,所以要調用CFRelease顯式釋放
NSString *aNSString = [[NSString alloc]initWithFormat:@"test"]; CFStringRef aCFString = (__bridge_retained CFStringRef) aNSString; // do something CFRelease(aCFString);
全部權給ARC,所以無需手動管理
CFStringRef aCFString = CFStringCreateWithCString(NULL, "test", kCFStringEncodingASCII); NSString *aNSString = (__bridge_transfer NSString *)aCFString; // do something