1.1什么是自動(dòng)引用計(jì)數(shù)
內(nèi)存管理中對(duì)引用采用自動(dòng)計(jì)數(shù)的計(jì)數(shù)
在LLVM編譯器中設(shè)置ARC為有效狀態(tài), 就無需再次鍵入retain或者release代碼
1.2內(nèi)存管理/引用計(jì)數(shù)
1.2.1概要
引用計(jì)數(shù)例子: 開關(guān)燈
- 最早進(jìn)入辦公室的人開燈
- 之后進(jìn)入辦公室的人需要照明
- 下班早離開辦公室的人不需要照明
- 最后離開辦公室的人關(guān)燈
通過需要照明人數(shù)來判斷是否有人在辦公室
| 狀態(tài) | 操作 | 分析 |
|---|---|---|
| 第一個(gè)人進(jìn)入辦公室 |
需要照明人數(shù)+1 |
計(jì)數(shù)值從0變成1, 需要開燈 |
| 每當(dāng)有人進(jìn)入辦公室 |
需要照明人數(shù)+1 |
如計(jì)數(shù)值從1變成2 |
| 每當(dāng)有人離開辦公室 |
需要照明人數(shù)-1 |
如計(jì)數(shù)值從2變成1 |
| 最后的人離開辦公室 |
需要照明人數(shù)-1 |
計(jì)數(shù)值從1變成0, 需要關(guān)燈 |
- 照明設(shè)備 - 對(duì)象
- 人- 對(duì)象的使用環(huán)境
| 對(duì)照明設(shè)備所做的動(dòng)作 | 對(duì)Objective-C對(duì)象所做的動(dòng)作 |
|---|---|
| 開燈 | 生成對(duì)象 |
| 需要照明 | 引用對(duì)象 |
| 不需要照明 | 釋放對(duì)象 |
| 關(guān)燈 | 回收對(duì)象 |
1.2.2內(nèi)存管理的思考方式
引用計(jì)數(shù)比較客觀的思考方式:
- 自己生成的對(duì)象, 自己所持有
- 非自己生成的對(duì)象, 自己也能持有
- 不再需要自己持有的對(duì)象時(shí)釋放
- 非自己持有的對(duì)象無法釋放
對(duì)象操作與Objective-C方法對(duì)應(yīng)
| 對(duì)象操作 | Objective-C方法 |
|---|---|
| 生成并且持有對(duì)象 | alloc/new/copy/mutableCopy等方法 |
| 持有對(duì)象 | retain方法 |
| 釋放對(duì)象 | release方法 |
| 廢棄對(duì)象 | dealloc方法 |
關(guān)于Objective-C內(nèi)存管理方法包含在Cocoa框架中, Cocoa框架中Foundation框架類庫的NSObject類負(fù)責(zé)內(nèi)存管理的職責(zé)
自己生成的對(duì)象, 自己所持有
alloc/new/copy/mutableCopy等方法生成的對(duì)象, 只有自己持有
// 以下方法, 所有objx對(duì)象引用計(jì)數(shù)器都會(huì)+1
id obj1 = [[NSObject alloc] init];
id obj2 = [[NSObject new];
id obj3 = [objc copy];
id obj4 = [objc mutableCopy];
非自己生成的對(duì)象, 自己也能持有
除alloc/new/copy/mutableCopy等方法之外的方法取得的對(duì)象, 因?yàn)榉亲约荷刹⒊钟? 所以自己不是該對(duì)象的持有者, 需要通過retain方法來持有
// 取得非自己生成并持有的對(duì)象
id obj = [NSMutableArray array]; // 取得的對(duì)象存在, 但自己不持有對(duì)象
[obj retain]; // 通過-retian方法使自己持有對(duì)象
不再需要自己持有的對(duì)象時(shí)釋放
自己持有的對(duì)象一旦不再需要, 持有者有義務(wù)釋放該對(duì)象, 釋放使用release方法
id obj1 = [[NSObject alloc] init]; // 自己生成并持有對(duì)象
[obj1 release]; // 釋放對(duì)象
id obj2 = [NSMutableArray array]; // 取得的對(duì)象存在, 但自己不持有對(duì)象
[obj2 retain]; // 通過-retian方法使自己持有對(duì)象
[obj2 release]; // 釋放對(duì)象
用alloc/new/copy/mutableCopy等方法生成并持有的對(duì)象, 或者使用retain方法持有的對(duì)象, 一旦不再需要, 務(wù)必要用release方法進(jìn)行釋放
非自己持有的對(duì)象無法釋放
用alloc/new/copy/mutableCopy等方法生成并持有的對(duì)象, 或者使用retain方法持有的對(duì)象, 由于持有者是自己, 所以在不需要該對(duì)象時(shí)需要將其釋放. 除此之外得到的對(duì)象絕對(duì)不能釋放, 否則會(huì)造成崩潰
1.2.3 alloc/retain/release/dealloc實(shí)現(xiàn)
通過GNUstep來說明的
GNUstep是Cocoa框架的互換框架, 與Cocoa實(shí)現(xiàn)方式比較一致, 通過其來了解Cocoa框架的實(shí)現(xiàn)
1.2.4蘋果的實(shí)現(xiàn)
通過對(duì)alloc類方法設(shè)置斷點(diǎn)追蹤程序的運(yùn)行, 得出執(zhí)行所調(diào)用的方法和函數(shù)
+ alloc
+ allocWithZone:
class_createInstance
calloc
alloc類方法首先調(diào)用allocWithZone:類方法, 然后調(diào)用class_createInstance函數(shù), 最后通過calloc來分配內(nèi)存塊
retainCount/retain/release實(shí)例方法所調(diào)用的方法和函數(shù)
- retainCount
__CFDoExternRefOperation
CFBasicHashGetCountOfKey
- retain
__CFDoExternRefOperation
CFBasicHashAddValue
- release
__CFDoExternRefOperation
CFBasicHashRemoveValue // 該方法返回0時(shí), -realse調(diào)用dealloc
1.2.5autorelease
autorealse自動(dòng)釋放, 更類似于C中的局部變量, 即超出作用域時(shí)對(duì)象實(shí)例的realease實(shí)例方法被調(diào)用
autorelease的具體使用方法:
- 生成并持有NSAutoreleasePool對(duì)象
- 調(diào)用已分配對(duì)象的autorelease實(shí)例方法
- 廢棄NSAutoreleasePool對(duì)象
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
id objc = [[NSObject alloc] init];
[obj autorelease];
[pool drain]; // 相當(dāng)于[obj release];
在Cocoa框架中, 相當(dāng)于程序主循環(huán)的NSRunLoop或者在其他程序可運(yùn)行的地方, 對(duì)NSAutoreleasePool對(duì)象進(jìn)程生成, 持有和廢棄處理.
在大量產(chǎn)生autorelease對(duì)象時(shí), 只要不廢棄NSAutoreleasePool對(duì)象, 那么生成的對(duì)象就不能被釋放, 有時(shí)會(huì)產(chǎn)生內(nèi)存不足的現(xiàn)象. 例如: 讀入大量圖像的同事改變其尺寸, 圖像文件讀入到NSData對(duì)象, 并從中生成UIImage對(duì)象, 改變對(duì)象尺寸后生成新的UIImage對(duì)象, 這種情況下會(huì)產(chǎn)生大量autorelease對(duì)象.
for (int i = 0; i < 圖像數(shù); ++i) {
// 讀入圖像
// 大量產(chǎn)生autorelease對(duì)象
// 由于沒有廢棄NSAutoreleasePool對(duì)象
// 最終導(dǎo)致內(nèi)存不足
[pool drain]; // 通過該方法, autorelease的對(duì)象被一起release
}
1.2.6autorelease實(shí)現(xiàn)
通過GNUstep, 我們能夠看到NSObject類的autorealse實(shí)例方法, 本質(zhì)就是調(diào)用NSAutoreleasePool對(duì)象的addObject類方法
- (id)autorelease {
[NSAutoreleasePool addobject: self];
}
1.2.7蘋果的實(shí)現(xiàn)
1.3ARC規(guī)則
1.3.1概要
引用計(jì)數(shù)式內(nèi)存管理的本質(zhì)部分在ARC中并沒有改變, ARC只是自動(dòng)地幫我們處理引用計(jì)數(shù)的相關(guān)部分
- 一個(gè)應(yīng)用程序可以ARC和MRC混合使用
- 設(shè)置ARC有效的 編譯方法:
- 使用clang3.0及其以上版本
- 指定編譯器屬性為'-fobjc-arc'
1.3.2內(nèi)存管理的思考方式
- 自己生成的對(duì)象, 自己所持有
- 非自己生成的對(duì)象, 自己也能持有
- 不再需要自己持有的對(duì)象時(shí)釋放
- 非自己持有的對(duì)象無法釋放
這一思考模式在ARC時(shí)也是可行的, 只是在源碼的技術(shù)方法上稍有不同. 具體有什么變化需要先理解ARC中追加的所有權(quán)聲明
1.3.3所有權(quán)修飾符
Objective-C編程中為了處理對(duì)象, 可將變量類型定義為id類型或者各種對(duì)象類型
ARC有效時(shí), id類型和對(duì)象類型同C語言其他類型不同, 其類型必須附加所有權(quán)修飾符, 所有權(quán)修飾符一共4種:
- __strong修飾符
- __weak修飾符
- __unsafe_unretained修飾符
- __autoreleasing修飾符
__strong修飾符
__strong修飾符是id類型和對(duì)象類型默認(rèn)的所有權(quán)修飾符
id obj = [[NSObject alloc] init];
// id和對(duì)象類型在沒有明確指定所有權(quán)修飾符時(shí), 默認(rèn)為__strong修飾符
id __strong obj = [[NSObject alloc] init];
在MRC模式下, 改源碼可以記述為
{
id obj = [[NSObject alloc] init];
[obj release];
}
如上述代碼所示, 所有__strong修飾符的變量obj在超出其變量作用域時(shí), 即在該變量被廢棄時(shí), 會(huì)釋放其被賦予的對(duì)象
如'strong'這個(gè)名詞所示, __strong修飾符表示對(duì)對(duì)象的"強(qiáng)引用". 持有強(qiáng)引用的變量在超出其作用于時(shí)被廢棄, 隨著強(qiáng)引用的失效, 引用的對(duì)象隨之釋放
關(guān)注下源代碼中關(guān)于對(duì)象的所有者部分
{
// 自己生成并且持有對(duì)象
id __strong obj = [[NSObject alloc] init];
// 取得非自己生成并持有的對(duì)象
id __strong obj2 = [NSMutableArray array];
} /*
* 變量超出其作用于, 強(qiáng)引用失效
* 自動(dòng)地釋放自己持有的對(duì)象
* 對(duì)象的所有者不存在, 因此廢棄該對(duì)象
*/
__strong修飾符的變量, 不僅只在變量作用域中, 在復(fù)制上也能夠正確的管理其對(duì)象的所有者.
另外__strong修飾符同之后的__weak修飾符和__autoreleasing修飾符一起, 可以保證將附有這些修飾符的自動(dòng)變量初始化為nil
id __strong obj0;
id __weak obj1;
id __autoreleasing obj2;
// 下面代碼與以上相同
id __strong obj0 = nil;
id __weak obj1 = nil;
id __autoreleasing obj2 = nil;
__weak修飾符
如果僅僅使用__strong修飾符, 無法解決 "循環(huán)引用" 的問題, 從而引發(fā)內(nèi)存泄露
- 所謂內(nèi)存泄漏就是應(yīng)當(dāng)廢棄的對(duì)象在超出其生命周期后繼續(xù)存在
__weak修飾符與__strong修飾符相反, 提供弱引用. 弱引用不能持有對(duì)象實(shí)例.
- 通過
__weak修飾符從而解決循環(huán)引用的問題 -
__weak修飾符還有另一優(yōu)點(diǎn): 在持有某對(duì)象的弱引用時(shí), 若該對(duì)象被廢棄, 則此弱引用將自動(dòng)失效且處于nil被賦值的狀態(tài)
可以通過__weak修飾符可避免循環(huán)引用, 通過檢查賦有__weak修飾符的變量是否為nil, 可以判斷被復(fù)制的對(duì)象是否已被廢棄
__unsafe_unretained修飾符
__unsafe_unretained修飾符, 是不安全的所有權(quán)修飾符. 盡管ARC的內(nèi)存管理是編譯器工作, 但附有__unsafe_unretained修飾符的變量不屬于編譯器的內(nèi)存管理對(duì)象
- 附有
__unsafe_unretained修飾符的變量同附有__weak修飾符的變量一樣, 不能持有對(duì)象. - 附有
__unsafe_unretained修飾的變量如果被廢棄, 該引用不會(huì)被自動(dòng)賦值為nil
在使用__unsafe_unretained修飾符時(shí), 賦值給附有__strong修飾符的變量時(shí), 有必要確認(rèn)被復(fù)制的對(duì)象確實(shí)存在
__autoreleasing修飾符
ARC有效時(shí)不能使用autorelease方法, 也不能使用`NSAutoreleasePool'類. 雖然autorelease無法直接使用, 但是在arc有效時(shí)autorelease功能是起作用的
@autoreleasepool {
id __autoreleasing obj = [[NSObject alloc] init];
}
指定@autoreleasepool快來替代NSAutoreleasePool類對(duì)象生成, 持有以及廢棄這一范圍. 對(duì)象賦值給附有__autoreleasing修飾符的變量, 等價(jià)于在MRC時(shí)調(diào)用對(duì)象的autorelease方法, 即對(duì)象唄注冊(cè)到autoreleasepool
在訪問附有__weak修飾符的變量時(shí)必須訪問注冊(cè)到autoreleasepool的對(duì)象, 因?yàn)?code>__weak修飾符只有對(duì)象的弱引用, 而在訪問引用對(duì)象的過程中, 該對(duì)象有可能被廢棄, 如果要把訪問對(duì)象注冊(cè)到autoreleasepool中, an么在@autore快結(jié)束之前都能卻別該對(duì)象的存在
id的指針或?qū)ο蟮闹羔樤跊]有顯示指定時(shí)會(huì)被附加上__autoreleasing修飾符
賦值給對(duì)象指針時(shí), 所有權(quán)修飾符必須一致
1.3.4規(guī)則
在ARC有效的情況下編譯代碼, 必須遵守以下原則
- 不能使用 retain/release/retainCount/autorealease
- 不能使用NSAllocateObject/NSDeallocateObject
- 必須遵守內(nèi)存管理方法的命名規(guī)則
- 不要顯式調(diào)用dealloc
- 使用@autoreleasepool快替代NSAutoreleasePool
- 不能使用區(qū)域(NSZone)
- 對(duì)象類型不能為C語言結(jié)構(gòu)體(struct/union)的成員
- 顯示轉(zhuǎn)換
id和void *
不能使用 retain/release/retainCount/autorealease
編譯器自動(dòng)使用了這些方法, 再次使用不符合內(nèi)存管理規(guī)范
在ARC有效時(shí), 使用這些方法會(huì)編譯出錯(cuò)
不能使用NSAllocateObject/NSDeallocateObject
一般通過NSObject類的alloc類方法來生成并持有Objective-C對(duì)象
在ARC有效時(shí), 使用這些方法會(huì)編譯出錯(cuò)
必須遵守內(nèi)存管理方法的命名規(guī)則
如1.2.2所述, 在ARC無效時(shí), 用于對(duì)象生成/持有的方法必須遵守以下命名規(guī)則
- alloc
- new
- copy
- mutableCopy
以上名稱開始的方法, 在返回對(duì)象時(shí), 必須返回給調(diào)用方法所應(yīng)當(dāng)持有的對(duì)象
在ARC有效時(shí)追加一條:
- init
以init開始的方法規(guī)則要比上述方法更嚴(yán)格, 該方法必須是實(shí)例方法, 并且必須返回對(duì)象, 返回的對(duì)象應(yīng)為id(instancetype)或該方法聲明類的對(duì)象類型, 亦或是該類的父類型或子類型, 該返回對(duì)象不注冊(cè)到autoreleasepool上, 基本知識(shí)對(duì)alloc方法返回的對(duì)象進(jìn)行初始化處理并返回該對(duì)象
不要顯式調(diào)用dealloc
無論ARC是否有效, 只要對(duì)象持有者不持有該對(duì)象, 對(duì)象就會(huì)被廢棄, 對(duì)象被廢棄時(shí)會(huì)自動(dòng)調(diào)用該對(duì)象的dealloc方法
- 在ARC無效時(shí),
dealloc方法中必須調(diào)用[super dealloc] - 在ARC有效時(shí),
dealloc方法中不能調(diào)用[super dealloc], 否則編譯出錯(cuò)
使用@autoreleasepool快替代NSAutoreleasePool
在ARC有效時(shí)不能使用NSAutoreleasePool類, 參考1.3.3
不能使用區(qū)域(NSZone)
雖說ARC有效時(shí)不能使用區(qū)域(NSZone), 但是如1.2.3所屬, 不論ARC是否有效, 區(qū)域在現(xiàn)在的運(yùn)行時(shí)系統(tǒng)中已被忽略
對(duì)象類型不能為C語言結(jié)構(gòu)體(struct/union)的成員
C語言結(jié)構(gòu)體中如果存在Objective-C對(duì)象類型變量, 會(huì)引起編譯錯(cuò)誤
因ARC把內(nèi)存管理的工作分配給編譯器, 所以編譯器必須能夠知道并管理對(duì)象的生存周期
要把對(duì)象類型變量加入到結(jié)構(gòu)體成員中時(shí) 可強(qiáng)制轉(zhuǎn)換為void *或者附加__unsafe_unretained修飾符, 如
// 注意, 附有__unsafe_unretained修飾符的變量不屬于編譯器的內(nèi)存管理對(duì)象, 如果使用時(shí)不注意賦值對(duì)象的所有者, 可能會(huì)遭遇內(nèi)存泄漏或程序崩潰
struct Data {
NSMutableArray __unsafe_unretained *array;
};
顯示轉(zhuǎn)換id和void *
在ARC無效時(shí), 以下代碼不會(huì)出錯(cuò)
id obj = [[NSObject alloc] init];
void *p = obj;
id o = p;
[o release];
但是在ARC有效時(shí)會(huì)引起編譯錯(cuò)誤
id類型或?qū)ο箢愋妥兞抠x值給void *或者逆向賦值時(shí)都需要進(jìn)行特定的轉(zhuǎn)換, 如果只想單純的賦值, 則可進(jì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更低, 如果使用不注意很可能引起程序崩潰
__bridge還有另外兩種轉(zhuǎn)換
-
__bridge_retained- 可使要轉(zhuǎn)換賦值的變量也持有所復(fù)制的對(duì)象
-
__bridge_transfer- 被轉(zhuǎn)換的變量所持有的對(duì)象在該變量唄賦值給轉(zhuǎn)換目標(biāo)變量之后隨之釋放
通過以上兩種轉(zhuǎn)換, 不適用id類型或者對(duì)象類型變量也可以生成, 持有以及釋放對(duì)象. 雖然可以這樣做, 但是在ARC中并不推薦這種方法
// ARC有效
void *p = (__bridge_retained void *)[[NSObject alloc] init];
(void)(__bridge_gransfer id)p
// ARC無效
id p = [[NSObject alloc] init];
[p release];
這些轉(zhuǎn)換多數(shù)在使用Objective-C對(duì)象與Core Foundation對(duì)象之間的相互轉(zhuǎn)變中
這部分還講了CoreFoundation和Foundation對(duì)象之間的轉(zhuǎn)換及使用注意
1.3.5屬性
當(dāng)ARC有效時(shí), Objective-C類的屬性也發(fā)生了變化, 以下可作為屬性聲明中的屬性來使用
| 屬性聲明的屬性 | 所有權(quán)修飾符 |
|---|---|
assign |
__unsafe_unretained修飾符 |
copy |
__strong修飾符(但是賦值的是被復(fù)制的對(duì)象) |
retain |
__strong修飾符 |
strong |
__strong修飾符 |
unsafe_unretained |
__unsafe_unretained修飾符 |
weak |
__weak修飾符 |
1.3.6數(shù)組
__unsafe_unretain修飾符以外的__strong/__weak/__autoreleasing修飾符保證其指定的變量初始化為nil.
根據(jù)不同的目的選擇使用NSMutableArray/NSMutableDictionary/NSMutableSet等Foundation框架的容器, 這些容器會(huì)恰當(dāng)?shù)某钟凶芳拥膶?duì)象并為我們管理這些對(duì)象
在__autoreleasing修飾的情況下, 因?yàn)榕c設(shè)想的使用方式有差異, 最好不要使用動(dòng)態(tài)數(shù)組, 由于__unsafe_unretained修飾符在編譯器的內(nèi)存管理對(duì)象之外, 所以與void *類型一樣, 只能作為C語言的指針類型來使用
1.4ARC的實(shí)現(xiàn)
ARC是Objective-C運(yùn)行時(shí)庫和編譯器進(jìn)行的內(nèi)存管理, ARC由一下工具, 類庫來實(shí)現(xiàn)
- clang(LLVM編譯器)3.0以上
- objc4 Objective-C運(yùn)行時(shí)庫493.9以上
本節(jié)圍繞clang匯編輸出和objc4庫源碼進(jìn)行說明, 具體代碼詳見書(讀這章之前需要一些runtime基礎(chǔ))
1.4.1 __strong修飾符
賦值給附有__strong修飾符的變量在實(shí)際使用中運(yùn)行原理
這一塊比較繞, 可以先看代碼然后看后面的總結(jié), 最后再繞回來看方法下面的論述
alloc/new/copy/mutableCopy等方法
{
id __strong obj = [[NSObject alloc] init];
}
通過程序匯編輸出得到原源代碼
/* 編譯器的模擬代碼 */
id obj = objc_msgSend(NSObject, @selector(alloc));
objc_msgSend(obj, @selector(init);
objc_release(obj)
通過原源代碼所以, 兩次調(diào)用objc_msgSend方法(alloc和init), 變量作用域結(jié)束時(shí)通過objc_release釋放對(duì)象, 雖然ARC不能使用release方法, 但是由此可知, 編譯器自動(dòng)插入了release.
其它構(gòu)造方法
{
id __srong obj = [NSMutableArray array];
}
編譯器原源代碼
id objc = objc_msgSend(NSMutableArray, @selector(array));
objc_retainAutoreleasedReturnValue(obj);
objc_release(obj);
最開始的array方法調(diào)用和最后變量作用域結(jié)束時(shí)的release與之前相同, 但是中間的objc_retainAutoreleasedReturnValue函數(shù)是什么?
- 它是用于 自己持有(retain)對(duì)象 的函數(shù), 但它持有的對(duì)象應(yīng) 為返回
注冊(cè)在autoreleasepool中對(duì)象的方法或是函數(shù)的返回值, 調(diào)用alloc/new/copy/mutableCopy以外的方法, 由編譯器插入該函數(shù). - 這種方法是成對(duì)的, 與之相對(duì)的是
objc_autoreleaseReturnValue, 它用于alloc/new/copy/mutableCopy以外的類的構(gòu)造方法等用于返回的對(duì)象的實(shí)現(xiàn)上
+ (id)array {
return [[NSMutableArray Alloc] init];
}
轉(zhuǎn)換后的原源碼使用了objc_autoreleaseReturnValue函數(shù)
+ (id)array {
id obj = id objc = objc_msgSend(NSMutableArray, @selector(array));
objc_msgSend(obj, @selector(init));
return objc_aotureleaseReturnValue(obj);
}
返回 注冊(cè)到autoreleasepool中對(duì)象 的方法使用了objc_autoreleaseReturnValue函數(shù)返回 注冊(cè)到autoreleasepool中的對(duì)象, 但是objc_autoreleaseReturnValue函數(shù)同objc_autorelease函數(shù)不同, 一般不僅限于注冊(cè)對(duì)象到autoreleasepool中.
objc_autoreleaseReturnValue函數(shù)會(huì)檢查使用該函數(shù)的方法/函數(shù) 調(diào)用方 的執(zhí)行命名列表, 如果方法/函數(shù)的 調(diào)用方 在調(diào)用了方法/函數(shù)后緊接著調(diào)用objc_retainAutoreleasedReturnValue函數(shù), 那么就不將返回的對(duì)象注冊(cè)到autoreleasepool中, 而是直接傳遞到方法/函數(shù)的 調(diào)用方
objc_retainAutoreleasedReturnValue函數(shù)與objc_retain函數(shù)不同, 它即便不注冊(cè)到autoreleasepool中而返回對(duì)象, 也能夠正確的獲取對(duì)象
通過objc_retainAutoreleasedReturnValue函數(shù)與objc_autoreleaseReturnValue函數(shù)的寫作, 可以不將對(duì)象注冊(cè)到autoreleasepool中而直接傳遞, 這一過程達(dá)到了最優(yōu)化.

說白了, 就是
objc_retainAutoreleasedReturnValue函數(shù)持有的對(duì)象應(yīng)是函數(shù)/方法的返回值, 這個(gè)返回值應(yīng)當(dāng)注冊(cè)在autoreleasepool中
objc_autoreleaseReturnValue函數(shù)會(huì)判斷自己所在的這個(gè)函數(shù)/方法的調(diào)用方之后有沒有調(diào)用objc_retainAutoreleasedReturnValue, 如果沒有, 就將返回值注冊(cè)到autoreleasepool中, 如果有就不注冊(cè)了, 而且它能讓objc_retainAutoreleasedReturnValue函數(shù)正確的獲取到對(duì)象
1.4.2 __weak修飾符
延伸閱讀: weak的生命周期:具體實(shí)現(xiàn)方法
- 若附有
__weak修飾符的變量所引用的對(duì)象被廢棄, 則將nil賦值給該變量 - 使用附有
__weak修飾符的變量, 即是使用注冊(cè)到autoreleasepool中的對(duì)象
{
// 假設(shè)obj附加__strong修飾符且被賦值
id __weak obj1 = obj;
}
轉(zhuǎn)換后的原源代碼
id obj1;
objc_initWeak(&obj1, obj);
objc_destroyWeak(&obj1);
objc_initWeak函數(shù)內(nèi)部
obj1 = 0;
objc_storeWeak(&obj1, obj;
objc_destroyWeak函數(shù)內(nèi)部