- 自動引用計(jì)數(shù) (ARC,Automatic Reference Counting)
1.1 什么是自動引用計(jì)數(shù)?
ARC是指內(nèi)存管理中對引用采用自動計(jì)數(shù)的技術(shù)。在LLVM編譯器中設(shè)置ARC為有效狀態(tài),就無需再次鍵入retain或者是release代碼。
1.2 內(nèi)存管理/引用計(jì)數(shù)


1.2.2 內(nèi)存管理的思考方式
從上面的內(nèi)容,我們可以得出這么一個(gè)結(jié)論:
1. 自己生成的對象,自己所持有。
2. 非自己生成的對象,自己也能持有。
3. 不再需要自己持有的對象時(shí)釋放。
4. 非自己持有的對象無法釋放。
除了以上四條提到的三個(gè)詞:“生成”、“持有”、“釋放”,還有另外一個(gè)詞:“廢棄”或者叫“銷毀”。

這些有關(guān)OC內(nèi)存管理的方法,實(shí)際上不包括在該語言中,而是包含在Cocoa框架中用于OS X、iOS 應(yīng)用開發(fā)。Cocoa框架中 Foundation 框架類庫的 NSObject 類擔(dān)負(fù)內(nèi)存管理的職責(zé)。OC內(nèi)存管理中的alloc、retain、release、dealloc方法分別指代 NSObject 類的alloc類方法、retain實(shí)例方法、release實(shí)例方法和dealloc實(shí)例方法。

自己生成的對象,自己所持有
使用以下名稱開頭的方法名意味著自己生成的對象只有自己持有:
- alloc
- new
- copy
- mutableCopy
copy -- 基于NSCopying協(xié)議實(shí)現(xiàn)協(xié)議的copyWithZone:方法生成并持有對象的副本。
mutableCopy -- 基于NSMutableCopying協(xié)議實(shí)現(xiàn)協(xié)議的mutableCopyWithZone:方法生成并持有對象的副本。
“自己”指的是“對象的使用環(huán)境”,但將之理解為編程人員“自身”也是沒錯的。
// [NSObject new]與[[NSObject alloc] init]是完全一致的。
id obj1 = [[NSObject alloc] init];
// or
id obj2 = [NSObject new];
非自己生成的對象,自己也能持有
本小節(jié)略有疑問,閱讀原書查看更多內(nèi)容。
不再需要自己持有的對象時(shí)釋放
id obj = [[NSObject alloc] init];
[obj release];
// 指向?qū)ο蟮闹羔橂m仍然保留在變量obj中,貌似能夠訪問,但對象已經(jīng)被釋放了,是決不可訪問的,這時(shí)候的obj已經(jīng)變成了*野指針*,為避免訪問報(bào)錯,可以將obj設(shè)置為空指針。
obj = nil;
// 因?yàn)榻o空指針發(fā)消息是不會報(bào)錯的。
用alloc/new/copy/mutableCopy方法生成并持有的對象,或者用retain方法持有的對象,一旦不再需要,務(wù)必要用release方法進(jìn)行釋放。

無法釋放非自己持有的對象
即只有當(dāng)你持有該對象時(shí),你才有權(quán)利釋放它,否則不要去執(zhí)行釋放操作;釋放過一遍了,不要嘗試再次釋放。
1.2.3 alloc/retain/release/dealloc 實(shí)現(xiàn)
-
GNUstep的實(shí)現(xiàn)
圖6·GNUstep中的實(shí)現(xiàn)機(jī)制 -
Apple的實(shí)現(xiàn)
圖7·通過引用計(jì)數(shù)表追溯對象
1.2.5 autorelease
顧名思義,autorelease就是自動釋放,這看上去很像ARC,但實(shí)際上它更類似于C語言中的自動變量(局部變量)的特性。自動變量的概念是程序執(zhí)行時(shí),若某自動變量超出其作用域,該自動變量將被自動廢棄。autorelease會像C語言的自動變量那樣來對待對象實(shí)例。當(dāng)超出其作用域(相當(dāng)于變量作用域)時(shí),對象實(shí)例的release實(shí)例方法被調(diào)用。另外,同C語言的自動變量不同的是,編程人員可以設(shè)定變量的作用域。
autorelease的具體使用方法如下:
- 生成并持有NSAutoreleasePool對象
- 調(diào)用已分配對象的autorelease實(shí)例方法
- 廢棄NSAutoreleasePool對象

NSAutoreleasePool對象的生存周期相當(dāng)于C語言變量的作用域。對于所有調(diào)用過autorelease實(shí)例方法的對象,在廢棄NSAutoreleasePool對象時(shí),都將調(diào)用release實(shí)例方法。
值得注意的是,在Cocoa框架中,相當(dāng)于程序主循環(huán)的NSRunLoop或者在其他程序可運(yùn)行的地方,對NSAutoreleasePool對象進(jìn)行生成、持有和廢棄處理。因此,開發(fā)者不一定非得使用NSAutoreleasePool對象來進(jìn)行開發(fā)工作。

盡管如此,不是代表你就可以不用手動管理autorelease的調(diào)用了,在大量產(chǎn)生autorelease的對象時(shí),只要不廢棄NSAutoreleasePool對象,那么生成的對象就不能被釋放,因此有時(shí)會產(chǎn)生內(nèi)存不足的現(xiàn)象。典型的例子就是讀入大量圖像的同時(shí),改變其尺寸等等一些列的操作,不停的消耗內(nèi)存,因此這時(shí)就需要我們手動創(chuàng)建NSAutoreleasePool對象,并適時(shí)廢棄,來優(yōu)化內(nèi)存。

另外,Cocoa框架中也有很多類方法用于返回autorelease的對象,比如NSMutableArray類的arrayWithCapacity類方法。
id array = [NSMutableArray arrayWithCapacity: 1];
// 等同于以下
id array = [[[NSMutableArray alloc] initWithCapacity: 1] autorelease];
1.2.6 autorelease 實(shí)現(xiàn)


更多內(nèi)容查看原書。
1.3 ARC 規(guī)則
1.3.1 概要
實(shí)際上“引用計(jì)數(shù)式內(nèi)存管理”的本質(zhì)部分在ARC中并沒有改變。就像“自動引用計(jì)數(shù)”這個(gè)名詞表示的那樣,ARC只是自動地幫助我們處理“引用計(jì)數(shù)”的相關(guān)部分。
在編譯單位上,可設(shè)置ARC有效或無效,這一點(diǎn)便能佐證上述結(jié)論。比如對每一個(gè)文件可選擇使用或不使用ARC。

設(shè)置ARC有效的編譯方法如下:
- 使用clang(LLVM編譯器)3.0或以上版本。
- 指定編譯器屬性為“-fobjc-arc”
Xcode4.2默認(rèn)設(shè)定為對所有的文件ARC有效。
1.3.2 內(nèi)存管理的思考方式
1. 自己生成的對象,自己所持有。
2. 非自己生成的對象,自己也能持有。
3. 不再需要自己持有的對象時(shí)釋放。
4. 非自己持有的對象無法釋放。
思考方式與非ARC模式下的是一樣的,只是在源代碼的記述方法上稍有不同。首先要理解ARC中追加的所有權(quán)聲明。
1.3.3 所有權(quán)修飾符
OC編程中為了處理對象,可將變量類型定義為id類型或各種對象類型。
所謂對象類型就是指向NSObject這樣的OC類的指針,例如“NSObject *”。id類型用于隱藏對象類型的類名部分,相當(dāng)于C語言中常用的“void *”。
ARC有效時(shí),id類型和對象類型同C語言其他類型不同,其類型上必須附加所有權(quán)修飾符。所有權(quán)修飾符一共有四種。
- __strong 修飾符
- __weak 修飾符
- __unsafe_unretained 修飾符
- __autoreleasing 修飾符
__strong 修飾符
__strong修飾符是id類型和對象類型默認(rèn)的所有權(quán)修飾符。也就是說,以下源代碼中的id類型的變量obj,實(shí)際上被附加了所有權(quán)修飾符。
id obj = [[NSObject alloc] init];
// 上面的代碼與下面是相同的
id __strong obj = [[NSObject alloc] init];
如同“strong”這個(gè)名詞所示,__strong 修飾符表示對對象的“強(qiáng)引用”。持有強(qiáng)引用的變量在超出其作用域時(shí)被廢棄,隨著強(qiáng)引用的失效,引用的對象會隨之釋放。
{
// 自己生成并持有對象
id __strong obj = [[NSObject alloc] init];
// 因?yàn)樽兞縪bj為強(qiáng)引用,所以自己持有對象
}
// 此時(shí)變量obj超出其作用域,強(qiáng)引用失效,所以自動的釋放了自己持有的對象。
// 對象的所有者不存在了,因此廢棄該對象。
附有__strong修飾符的變量之間可以相互賦值。
id __strong obj0 = [[NSObject alloc] init];
id __strong obj1 = [[NSObject alloc] init];
id __strong obj2 = nil;
obj0 = obj1;
obj2 = obj0;
obj1 = nil;
obj0 = nil;
obj2 = nil;
上面的代碼,三個(gè)變量所指向的2個(gè)對象都能夠被正確的釋放(詳細(xì)解釋參考原書)??梢钥闯觯琠_strong修飾符的變量,不僅只在變量作用域中,在賦值上也能夠正確地管理其對象的所有者。
也可以在方法參數(shù)上,使用附有__strong修飾符的變量。
Test.h
@interface Test : NSObject {
id __strong obj_;
}
-(void)setObject:(id __strong)obj;
@end
Test.m
@implementation Test
- (instancetype)init
{
self = [super init];
return self;
}
- (void)setObject:(id)obj {
obj_ = obj;
}
main.m
{
id __strong test = [[Test alloc] init];
[test setObject: [[NSObject alloc] init]];
}
下面來解釋一下上面的代碼執(zhí)行結(jié)果。
- test變量,持有Test對象的強(qiáng)引用。
- Test對象的obj_成員,持有NSObject對象的強(qiáng)引用。
- 因?yàn)閠est變量超出作用域,強(qiáng)引用失效,所以自動釋放Test對象。
- Test對象的所有者不存在,因此廢棄該對象。
- 廢棄Test對象的同時(shí),Test對象的obj_成員也被廢棄,NSObject對象的強(qiáng)引用失效,自動釋放NSObject對象。
- NSObject對象的所有者不存在,因此廢棄該對象。
因此,__strong修飾符,使得無需額外的工作便可使用于類成員變量和方法參數(shù)中。
另外,__strong修飾符同后面將要講到的__weak修飾符和__autoreleasing修飾符一起,可以保證將附有這些修飾符的自動變量初始化為nil。
id __strong obj0;
id __weak obj1;
id __autoreleasing obj2;
// 等同于如下:
id __strong obj0 = nil;
id __weak obj1 = nil;
id __autoreleasing obj2 = nil;
總結(jié):

__weak 修飾符
__weak修飾符的引入是為了解決引用計(jì)數(shù)式內(nèi)存管理中必然會發(fā)生的“循環(huán)引用”的問題。

我們來看一個(gè)循環(huán)引用的例子:
{
id test0 = [[Test alloc] init];
id test1 = [[Test alloc] init];
[test0 setObject: test1];
[test1 setObject: test0];
}

循環(huán)引用容易發(fā)生內(nèi)存泄漏。所謂內(nèi)存泄漏就是應(yīng)當(dāng)廢棄的對象在超出其生存周期后繼續(xù)存在。
一個(gè)對象持有其自身時(shí),也會發(fā)生循環(huán)引用。

這時(shí)候就該__weak修飾符上場了,__weak修飾符與__strong修飾符相反,提供弱引用。弱引用不能持有對象實(shí)例。
看看這個(gè)修改后的實(shí)例:

__weak修飾符還有另一優(yōu)點(diǎn)。在持有某對象的弱引用時(shí),若該對象被廢棄,則此弱引用將自動失效且處于nil被賦值的狀態(tài)(空弱引用)。
id __weak obj1 = nil;
{
id __strong obj0 = [[NSObject alloc] init];
obj1 = obj0;
NSLog(@"A: %@", obj1);
}
NSLog(@"B: %@", obj1);
// 執(zhí)行結(jié)果如下:
A: <NSObject: 0x753e180>
B: (null)
__weak修飾符只能用于iOS5以上及OS X Lion以上版本,在iOS4及OS X Snow Leopard中,可以使用__unsafe_unretained修飾符來代替。
更多詳細(xì)內(nèi)容查看原書。
__unsafe_unretained 修飾符
__unsafe_unretained修飾符正如其名unsafe所示,是不安全的所有權(quán)修飾符。盡管ARC式的內(nèi)存管理是編譯器的工作,但附有__unsafe_unretained修飾符的變量不屬于編譯器的內(nèi)存管理對象。這一點(diǎn)在使用時(shí)要注意。
id __unsafe_unretained obj = [[NSObject alloc] init];
編譯器會給出警告,提示和使用__weak修飾符時(shí)類似。警告,自己生成并持有的對象不能繼續(xù)為自己所有,所以生成的對象會立即被釋放。
id __unsafe_unretained obj1 = nil;
{
id __strong obj0 = [[NSObject alloc] init];
obj1 = obj0;
NSLog(@"A: %@", obj1);
}
NSLog(@"B: %@", obj1);
// 執(zhí)行結(jié)果如下:
A: <NSObject: 0x753e180>
B: <NSObject: 0x753e180>
運(yùn)行到NSLog(@"B: %@", obj1);時(shí),其實(shí)obj1所指向的對象已經(jīng)被釋放了,最后一行NSLog只是碰巧正常運(yùn)行而已。雖然訪問了已經(jīng)被廢棄的對象,但應(yīng)用程序在個(gè)別運(yùn)行狀況下才會崩潰。所以,有可能程序在執(zhí)行到那一行時(shí),發(fā)生野指針錯誤,引發(fā)崩潰。野指針:變量地址指向了一塊已經(jīng)被廢棄了的內(nèi)存塊,試圖訪問方法、變量,從而引發(fā)崩潰。
__unsafe_unretined的存在是為了解決在iOS4及OS X Snow Leopard中的應(yīng)用程序下使用,避免循環(huán)引用的修飾符,當(dāng)然,使用時(shí)要注意,在訪問__unsafe_unretained修飾符變量時(shí)要確保對象存在,不然程序會崩潰。
小結(jié):__weak和__unsafe_unretained的區(qū)別就在于,__weak屬于ARC范疇,ARC自動管理由__weak修飾符修飾的變量,在指向的對象被廢棄時(shí),自動將變量置為nil,而__unsafe_unretained不屬于ARC管理范疇,不會自動將變量置為nil,需要使用者自己判斷。
__autoreleasing 修飾符
ARC有效時(shí)autorelease會如何?實(shí)際上,后面講到的原則也會說明(參考1.3.3節(jié)),不能使用autorelease方法。另外,也不能使用NSAutoreleasePool類。這樣一來,雖然autorelease無法直接使用,但實(shí)際上,ARC有效時(shí)autorelease功能是起作用的。
ARC無效時(shí)的寫法
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
id obj = [[[NSObject alloc] init] autorelease];
[pool drain];
ARC有效時(shí)的寫法
@autoreleasepool {
id __autoreleasing obj = [[NSObject alloc] init];
}
在ARC中,通過“@autoreleasepool塊”來替代非ARC中的“NSAutoreleasePool類對象生成、持有以及廢棄”這一范圍。
可以這么理解,在ARC有效時(shí),用@autoreleasepool塊替代NSAutoreleasePool類,用附有__autoreleasing修飾符的變量替代autorelease方法。

但是要知道,顯式地附加 __autoreleasing 修飾符同顯式地附加 __strong 修飾符一樣罕見。
我們通過實(shí)例來看看為什么非顯式地使用 __autoreleasing 修飾符也可以。
取得非自己生成并持有的對象時(shí),如同一下源代碼,雖然可以使用alloc/new/copy/mutableCopy以外的方法來取得對象,但該對象已被注冊到了 autoreleasepool。這同在ARC無效時(shí)取得調(diào)用了 autorelease 方法的對象是一樣的。這是由于編譯器會檢查方法名是否以alloc/new/copy/mutableCopy開始,如果不是則自動將返回值的對象注冊到 autoreleasepool。
另外,根據(jù)后面要講到的遵守內(nèi)存管理方法命名規(guī)則(參考1.3.4節(jié)),init方法返回值的對象不注冊到 autoreleasepool。
@autoreleaspool {
id __strong obj = [[NSMutableArray array];
}
來看看到底發(fā)生了什么:

再來看看源代碼的調(diào)用過程:

雖然__weak修飾符是為了避免循環(huán)引用而使用的,但在訪問附有__weak修飾符的變量時(shí),實(shí)際上必定要訪問注冊到autoreleasepool的對象。
看下面的例子:
id __strong obj0 = [[NSObject alloc] init];
id __weak obj1 = obj0;
NSLog(@"class=%@", [obj1 class]);
以下源代碼與此相同:
id __strong obj0 = [[NSObject alloc] init];
id __weak obj1 = obj0;
id __autoreleasing tmp = obj1;
NSLog(@"class=%@", [tmp class]);
為什么在訪問附有__weak修飾符的變量時(shí)必須訪問注冊到autoreleasepool的對象呢?這是因?yàn)開_weak修飾符只持有對象的弱引用,而在訪問引用對象的過程中,該對象有可能被廢棄。如果把要訪問的對象注冊到autoreleasepool中,那么在@autoreleasepool塊結(jié)束之前都能確保該對象存在。
id的指針或?qū)ο蟮闹羔樤跊]有顯式指定時(shí)會被附加上__autoreleasing修飾符,這部分重點(diǎn)內(nèi)容較多,也較難以理解,查看原書。
注意,可借助強(qiáng)大的非公開函數(shù)_objc_autoreleasePoolPrint()方法來查看自動釋放池的狀態(tài)

專欄:__strong修飾符/__weak修飾符

1.3.4 規(guī)則
在ARC有效的情況下編譯源代碼,必須遵守一定的規(guī)則。下面就是具體的ARC的規(guī)則。
- 不能使用retain/release/retainCount/autorelease
- 不能使用NSAllocateObject/NSDeallocateObject
- 必須遵守內(nèi)存管理的方法命名規(guī)則
- 不能顯式調(diào)用dealloc
- 使用@autoreleasepool塊替代NSAutoreleasePool
- 不能使用區(qū)域(NSZone)
- 對象型變量不能作為C語言結(jié)構(gòu)體(struct/union)的成員
- 顯式轉(zhuǎn)換“id”和“void *”
下面詳細(xì)介紹各項(xiàng)。
不能使用retain/release/retainCount/autorelease
內(nèi)存管理是編譯器的工作,因此沒有必要再使用內(nèi)存管理的方法。這段話摘自蘋果的官方說明:“設(shè)置ARC有效時(shí),無需再次輸入retain或者是release代碼?!?/strong>實(shí)際上,如果在ARC有效時(shí),調(diào)用這些方法,編譯器是會報(bào)錯的,因此可以把這句話更準(zhǔn)確的描述為:“設(shè)置ARC有效時(shí),禁止再次鍵入retain或者是release代碼?!?/strong>
總之,只能在ARC無效且手動進(jìn)行內(nèi)存管理時(shí)使用retain/release/retainCount/autorelease方法。
不能使用NSAllocateObject/NSDeallocateObject
NSAllocateObject函數(shù)用于ARC無效時(shí)的NSObject類的alloc類方法,用于生成并持有對象的。同樣的,也禁止使用用于釋放對象的NSDeallocateObject函數(shù)。
須遵守內(nèi)存管理的方法命名規(guī)則
如1.2.2節(jié)所示,在ARC無效時(shí),用于對象生成/持有的方法必須遵守以下命名規(guī)則。
- alloc
- new
- copy
- mutableCopy
以上述名稱開始的方法在返回對象時(shí),必須返回給調(diào)用方所應(yīng)當(dāng)持有的對象。這在ARC有效時(shí)也一樣,返回的對象完全沒有改變。只是在ARC有效時(shí)要追加一條命名規(guī)則。 - init
以init開始的方法的規(guī)則要比 alloc/new/copy/mutableCopy 更嚴(yán)格。該方法必須是實(shí)例方法,并且必須要返回對象。返回的對象應(yīng)為 id類型或該方法聲明類的對象類型,抑或是該類的超類型或子類型。該返回對象并不注冊到autoreleasepool上?;旧现皇菍?code>alloc方法返回值的對象進(jìn)行初始化處理并返回該對象。
其他拓展自定義的命名規(guī)則舉例如下:
-(id)initWithObject:(id) obj;
-(id)initWithName:(NSString *)name age:(int)age;
不要顯式調(diào)用dealloc
無論ARC是否有效,只要對象的所有者都不持有該對象,該對象就被廢棄。對象被廢棄時(shí),不管ARC是否有效,都會調(diào)用對象的dealloc方法。
- (void) dealloc {
/* 此處運(yùn)行該對象被廢棄時(shí)必須實(shí)現(xiàn)的代碼 */
...
[super dealloc];// 必須放在最后調(diào)用(ARC無效時(shí)才手動調(diào)用,ARC有效時(shí)不允許調(diào)用)
}
比如使用C語言庫時(shí),在該庫內(nèi)部分配緩存時(shí),如以下所示,dealloc方法需要通過free來釋放留出的內(nèi)存。
- (void) dealloc {
free(buffer_);
}
dealloc方法在大多數(shù)情況下還適用于刪除已注冊的代碼或者觀察者對象。
- (void) dealloc {
[[NSNotificationCenter defaultCenter] removeObserver: self];
}
另外一定注意一點(diǎn),在ARC無效時(shí),重寫了dealloc方法后,[super dealloc];必須放在最后調(diào)用。
使用@autoreleasepool塊替代NSAutoreleasePool:參考1.3.3節(jié)
不能使用區(qū)域(NSZone)
雖說ARC有效時(shí),不能使用區(qū)域(NSZone)。正如前所述(參考1.2.3節(jié)),不管ARC是否有效,區(qū)域在現(xiàn)在的運(yùn)行時(shí)系統(tǒng)(編譯器宏OBJC2被設(shè)定的環(huán)境)中已單純地被忽略。
對象型變量不能作為C語言結(jié)構(gòu)體的成員
下面的代碼會引發(fā)編譯錯誤:
struct Data {
NSMutableArray *array;
};
編譯錯誤:error: ARC forbids Objective-C objcs in structs or unions
NSMutableArray *array;
要把對象型變量加入到結(jié)構(gòu)體成員中時(shí),可強(qiáng)制轉(zhuǎn)換為 void * 或是附加前面所述的 __unsafe_unretained 修飾符。
struct Data {
NSMutableArray __unsafe_unretained *array;
};
如前所述,附有 __unsafe_unretained 修飾符的變量不屬于編譯器的內(nèi)存管理對象。如果管理時(shí)不注意賦值對象的所有者,便有可能遭遇內(nèi)存泄漏或程序崩潰,在使用時(shí)要多加注意。
顯式轉(zhuǎn)換 id 和 void*
在ARC無效時(shí),像以下代碼這樣將id變量強(qiáng)制轉(zhuǎn)換void *變量并不會出問題。
/* ARC無效 */
id obj = [[NSObject alloc] init];
void *p = obj;
id o = p;
[o release];
但是在ARC有效時(shí)這便會引起編譯錯誤,這種操作不被允許。
id型或?qū)ο笮妥兞抠x值給void *或者逆向賦值時(shí)都需要進(jìn)行特定的轉(zhuǎn)換。如果只想單純地賦值,則可以使用“__bridge 轉(zhuǎn)換”。
id obj = [[NSObject alloc] init];
void *p = (__bridge void *)obj;
id o = (__bridge id)p;
像這樣,通過“__bridge 轉(zhuǎn)換”,id和void *就能通過互相轉(zhuǎn)換。
但是轉(zhuǎn)換為 void * 的__bridge 轉(zhuǎn)換,其安全性與賦值給 __unsafe_unretained 修飾符相近,甚至?xí)?。如果管理時(shí)不注意賦值對象的所有者,就會出現(xiàn)懸垂指針(野指針)而導(dǎo)致程序崩潰。
__bridge轉(zhuǎn)換中還有另外兩種轉(zhuǎn)換,分別是“__bridge_retained 轉(zhuǎn)換”和“__bridge_transfer 轉(zhuǎn)換”。
id obj = [[NSObject alloc] init];
void *p = (__bridge_retained void *)obj;
__bridge_retained 轉(zhuǎn)換可使要轉(zhuǎn)換賦值的變量也持有所賦值的對象。
__bridge_transfer 轉(zhuǎn)換提供與此相反的動作,被轉(zhuǎn)換的變量所持有的對象在該變量被賦值給轉(zhuǎn)換目標(biāo)變量后隨之釋放。相當(dāng)于是做了“轉(zhuǎn)移”(乾坤大挪移 ̄□ ̄||)。
同__bridge_retained轉(zhuǎn)換與retain類似,__bridge_transfer轉(zhuǎn)換與release相似。在給id obj賦值時(shí)retain即相當(dāng)于 __strong修飾符的變量。
如果使用以上兩種轉(zhuǎn)換,那么不使用id型或?qū)ο笮妥兞恳部梢陨?、持有以及釋放對象。雖然可以這么做,但在ARC中并不推薦這種方法。
void *p = (__bridge_retained void *)[[Person alloc] initWithName:@"CJL" age:29];
NSLog(@"class=%@", [(__bridge id)p class]);
(void)(__bridge_transfer id)p;
// 打印Person的dealloc方法,發(fā)現(xiàn)方法被調(diào)用了
這些轉(zhuǎn)換多數(shù)使用在OC對象與CoreFoundation對象之間的相關(guān)變換中。
專欄:OC對象與CoreFoundation對象

更多內(nèi)容查看原書。
1.3.5 屬性
當(dāng)ARC有效時(shí),OC類的屬性也會發(fā)生變化。
@property(nonatomic, strong) NSString *name;
當(dāng)ARC有效時(shí),以下可作為這種屬性聲明中使用的屬性來用。

1.3.6 數(shù)組
...

