OC采用了ARC之后編譯器給我們的代碼插入內(nèi)存管理代碼。
__strong
聲明一個(gè)對(duì)象,默認(rèn)是以__strong修飾的,當(dāng)沒有任何地方引用這個(gè)對(duì)象時(shí),對(duì)象會(huì)釋放。
// ARC下的普通變量的傳值
obj1 = obj2;
// ARC下編譯器會(huì)改寫為
// 新引用了obj2
// [obj2 reatain];
// 由于不再引用obj1
// [obj1 release];
// 完成賦值操作
// obj1 = obj2;
__autoreleasing
那么對(duì)于今天要說的__autoreleasing類型的變量呢, 被__autoreleasing修飾的變量特點(diǎn)是在當(dāng)前autoreleasepool作用域內(nèi)有效,出了當(dāng)前的autoreleasepool會(huì)被自動(dòng)釋放,不同于默認(rèn)的__strong變量,沒有引用時(shí)才會(huì)釋放。
// autoreleasing變量和普通變量傳值
NSObject * __autoreleasing auto1 = nil;
auto1 = obj1;
// ARC下編譯器會(huì)改寫
// 因?yàn)閍uto1需要保證引用對(duì)象在當(dāng)前autoreleasepool作用域內(nèi)有效
// [obj1 retain];
// [obj1 autorelease];
// auto1 = obj1;
// autoreleasing變量和autoreleasing變量傳值
auto1 = auto2;
// ARC下編譯器不需要改寫,因?yàn)閍uto2已經(jīng)是在當(dāng)前autoreleasepool作用域內(nèi)有效
// auto1 = obj1;
我們注意到__autoreleasing對(duì)象之間傳值不需要做任何處理,這是一個(gè)很好的特性,二級(jí)指針傳遞對(duì)象時(shí),接收和被傳遞的對(duì)象都需要被修飾成__autoreleasing,這樣的話ARC下編譯器不需要對(duì)傳遞過程做任何干預(yù),實(shí)際上要在二級(jí)指針傳值過程中自動(dòng)插入代碼并不太容易。
- (void)autoreleasingTestCase {
// 獲取方法返回的error
NSError * __autoreleasing error = nil;
[self autoreleasingTestForError:&error];
//@note:
// 如果我們寫的不標(biāo)準(zhǔn)
// NSError * error = nil;
// [self autoreleasingTestForError:&error];
// 實(shí)際代碼被改寫成這樣,
// 所以我們會(huì)發(fā)現(xiàn):autoreleasingTestForError打印errotPtr地址和&error不一致
// NSError * error = nil;
// NSError * __autoreleasing tmp = error;
// [self autoreleasingTestForError:&tmp];
// error = tmp;
}
// (NSError * __autoreleasing *)error表示error是指向一個(gè)__autoreleasing修飾的error對(duì)象
// @note:
// 如果我們寫成這樣(NSError **)error,實(shí)際上編譯器會(huì)認(rèn)為是(NSError * __autoreleasing *)error
// 這點(diǎn)可以通過自動(dòng)補(bǔ)全的提示發(fā)現(xiàn),提示是帶有__autoreleasing的
// 雖然使用上沒有問題,但是依然建議按照規(guī)范來聲明
- (void)autoreleasingTestForError:(NSError * __autoreleasing *)errorPtr {
NSError * __autoreleasing errorObj = [[NSError alloc]init];
// 給外部傳入的error變量賦值
*errorPtr = errorObj;
// @note:
// 如果errorObj不是__autoreleasing修飾的,那么編譯器會(huì)做一些修改
// NSError * errorObj = [[NSError alloc]init];
// NSError * __autoreleasing tmp = errorObj;
// *errorPtr = tmp;
}
盡管編譯器做了容錯(cuò)處理,在明白了__autoreleasing的特性之后,依然建議按照規(guī)范的格式編寫代碼,編譯器的容錯(cuò)并不一定可靠或者會(huì)帶來不必要的開銷。