title: ARC規(guī)則
date: 2016-03-17 16:49:05
categories: iOS
tags: Objective-C高級編程 iOS與OS X多線程和內(nèi)存管理
作者:秋兒(lvruifei@foxmail.com)
學(xué)習(xí)筆記 二 之《Objective-C高級編程 iOS與OS X多線程和內(nèi)存管理》
第一章:自動引用計數(shù)
ARC 規(guī)則
ARC 所有權(quán)修飾符:
-
__strong:
對對象強(qiáng)引用,變量超出其作用域時被廢棄,強(qiáng)引用失效,對象也隨之釋放(id 類型和對象類型默認(rèn)為 __strong 修飾符)
__weak:
在持有某對象的弱引用時,若對象被廢棄,則此弱引用將自動失效且處于nil 被賦值的狀態(tài)(空弱引用)。只能用于 iOS5 和 OS X Lion 以上版本,以下可使用 __unsafe_unretained 修飾符來代替。
-
__unsafe_unretained:
被修飾的變量不屬于編譯器的內(nèi)存管理對象,是 __weak 的代替
-
__autoreleasing:
@autoreleasepool 塊代替 NSAutoreleasePool 類對象生成,持有,廢棄這一范圍
__autoreleasing 修飾符 等價于在 ARC 無效時調(diào)用對象的 autorelease 方法
編譯器會檢查方法名是否是以 alloc/new/copy/mutableCopy 開始,不是,則自動將返回值得對象注冊到 autoreleasepool
訪問 __weak 修飾符的變量時必須訪問注冊到 autoreleasepool 的對象
id 的指針或?qū)ο蟮闹羔槙J(rèn)附加上 __autoreleasing 修飾符
賦值給對象指針時,所有權(quán)修飾符必須一致:
NSError *error = nil; NSError * __strong *pError = &error; NSError _weak *error = nil; NSError * __weak *pError = &error;
NSRunLoop 等實(shí)現(xiàn)不論 ARC 有效還是無效,均能夠隨時釋放注冊到 autoreleasepool 中的對象。
ARC 無效時 @autoreleasepool 塊 _objc_autoreleasePoolPrint() 均能使用。
ARC 規(guī)則:
-
不能使用 retain/release/retainCount/autorelease:
內(nèi)存管理是編譯器的工作
不能使用 NSAllocateObject/NSDeallocateObject
-
需遵守內(nèi)存管理的方法命名規(guī)則:
init 開始的方法返回的對象并不注冊到autoreleasepool 上
init 方法返回的對象應(yīng)為 id 類型或該方法聲明類的對象類型,或者是該類的超類型或子類型
不要顯式調(diào)用 dealloc
使用 @autoreleasepool 塊替代 NSAutoreleasePool
-
不能使用區(qū)域(NSZone):
不管 ARC 是否有效,區(qū)域在現(xiàn)在的運(yùn)行時系統(tǒng)中已單純的被忽略
-
對象型變量不能作為 C 語言結(jié)構(gòu)體(struct/union)的成員:
要把對象型變量加入到結(jié)構(gòu)體成員中時,可強(qiáng)制轉(zhuǎn)換為 void * 或者是附加 __unsafe_unretained 修飾符
struct Data { NSMutableArray __unsafe_unretained *array; };
-
顯式轉(zhuǎn)換 "id" 和 "void *"
在 ARC 無效時,將 void * 變量賦值給 id 變量,調(diào)用其實(shí)例方法,運(yùn)行時不會有問題
//ARC 無效 id obj = [[NSObject alloc] init]; void *p = obj; id o = p; [o release];
在 ARC 有效時,上面的代碼會引起編譯錯誤。id 型或?qū)ο笮妥兞抠x值給 void * 或者逆向賦值時都需要進(jìn)行特定的轉(zhuǎn)換。如果只想單純地賦值,則可以使用 “__bridge 轉(zhuǎn)換”
id obj = [[NSObject alloc] init]; void *p = (__bridge void *)obj; id o = (__bridge id)p;
轉(zhuǎn)換為 void * 的 __bridge 轉(zhuǎn)換,其安全性與賦值給 __unsafe_unretained 修飾符相近,甚至更低。如果管理時不注意賦值對象的所有者,就會因懸垂指針而導(dǎo)致程序崩潰。
__bridge 轉(zhuǎn)換中還有 “__bridge_retained 轉(zhuǎn)換” 和 “__bridge_transfer轉(zhuǎn)換”
- __bridge_retained 使要轉(zhuǎn)換賦值的變量也持有所賦值的對象, 與retain 相似
- __bridge_transfer 與上面的相反,被轉(zhuǎn)換的變量所持有的對象在該變量被賦值給轉(zhuǎn)換目標(biāo)變量后隨之釋放,與 release 相似
Objective-C 對象和 Core Foundation 對象,后者主要使用在用 C 語言編寫的 Core Foundation 框架中,使用引用計數(shù)的對象。兩者區(qū)別很小,不同之處只在于由哪一個框架所生成。一旦生成,便能在不同的框架中使用。
CFMutableArrayRef cgObject = NULL;
{
id obj = [[NSMutableArray alloc] init];
cfObject = CFBridgeRetain(obj);
CFShow(cfObject);
printf("retain count = %d\n",CFGetRetainCount(cfObject));// 2
}
printf("retain count after scope = %d\n",CFGetRetainCount(cfObject));// 1
CFRelease(cfObject);
__bridge_retained 轉(zhuǎn)換 可以代替 CFBridgeRetain,當(dāng)然,__bridge_transfer 轉(zhuǎn)換也可以替代 CFBridgeRelease
屬性:
屬性聲明的屬性 | 所有權(quán)修飾符 |
---|---|
assin | __unsafe_unretained 修飾符 |
copy | __strong 修飾符(但是賦值的是被復(fù)制的對象) |
retain | __strong 修飾符 |
strong | __strong 修飾符 |
unsafe_unretained | __unsafe_unretained 修飾符 |
weak | __weak 修飾符 |
聲明類成員變量時,如果同屬性聲明中的屬性不一致,則會引起編譯錯誤,如:
// 錯誤
id obj;
@property (nonatomic, weak) id obj;
// 正確
id __weak obj;
@property (nonatomic, weak) id obj;
// 正確
id obj;
@property (nonatomic, strong) id obj;
數(shù)組:
數(shù)組超出其變量作用域時,數(shù)組中各個附有 __strong 修飾符的變量也隨之失效,其強(qiáng)引用消失,對象隨之釋放。
- calloc 函數(shù)分配內(nèi)存會使分配區(qū)域初始化為0
- malloc 函數(shù)分配內(nèi)存后區(qū)域沒有被初始化0,可用 memset 等函數(shù)將內(nèi)存填充為 0
ARC 的實(shí)現(xiàn):
ARC 是由編譯器進(jìn)行內(nèi)存管理,但是需要 Objective-C 運(yùn)行時庫的協(xié)助
- clang(LLVM 編譯器)3.0 以上
- objc4 Objective-C 運(yùn)行時庫 493.9 以上
以下內(nèi)容待學(xué)
__strong 修飾符:
__weak 修飾符:
__autoreleasing 修飾符: