《Objective-C高級(jí)編程》自動(dòng)引用計(jì)數(shù) 閱讀筆記 item2(ARC規(guī)則及其實(shí)現(xiàn))

《Objective-C高級(jí)編程》自動(dòng)引用計(jì)數(shù) 閱讀筆記系列

《Objective-C高級(jí)編程》自動(dòng)引用計(jì)數(shù) 閱讀筆記 item1(內(nèi)存管理/引用計(jì)數(shù))
《Objective-C高級(jí)編程》自動(dòng)引用計(jì)數(shù) 閱讀筆記 item2(ARC規(guī)則及其實(shí)現(xiàn))

1.3 ARC規(guī)則

1.3.1 設(shè)置ARC有效的編譯方法如下:

  • 使用clang(LLVM編譯器)3.0或以上版本
  • 指定編譯器屬性為"-fobjc-arc"

1.3.2 引用計(jì)數(shù)式內(nèi)存管理的思考方式就是在ARC有效時(shí)同樣適用

1.3.3 所有權(quán)修飾符

概念

對(duì)象類型:*** 指向NSObject這樣的Objective-C類的指針,如“NSObject * ”咱旱。 **
id類型:*** 用于隱藏對(duì)象類型的類名部分乘寒,相當(dāng)于C語(yǔ)言中的“void *”祖凫。 **

ARC有效時(shí)摔癣,對(duì)象類型和id類型必須附加所有權(quán)修飾符楞捂,如下:

  • __strong修飾符
  • __weak修飾符
  • __unsafe_unretained修飾符
  • __autoreleasing修飾符

*** __strong修飾符 ***

__strong修飾符是id類型和對(duì)象類型默認(rèn)的所有權(quán)修飾符烧给。
源碼如下:

{
   id __strong obj = [[NSObject alloc] init];
}

附有__strong修飾符的變量obj在超出其變量作用域時(shí)梁丘,即在該變量被廢棄時(shí)侵浸,會(huì)釋放其被賦予對(duì)象。

關(guān)鍵知識(shí)點(diǎn):

  • __strong修飾符表示對(duì)對(duì)象的”強(qiáng)引用“氛谜。持有強(qiáng)引用的變量在超出其作用域時(shí)被廢棄掏觉,隨著強(qiáng)引用的失效,引用的對(duì)象會(huì)隨之釋放混蔼。
  • 附有__strong修飾符的變量之間可以相互賦值履腋。通過(guò)相互賦值,可以使得變量對(duì)對(duì)象的強(qiáng)引用失效惭嚣,從而釋放原先持有的對(duì)象遵湖,轉(zhuǎn)而持有由另外一個(gè)變量賦值的新的對(duì)象的強(qiáng)引用。
  • 即時(shí)是Objective-C類成員變量晚吞,也可以在方法參數(shù)上延旧,使用附有__strong修飾符的變量
  • __strong修飾符可以確保將附有__strong修飾符的自動(dòng)變量(局部變量)初始化為nil(該規(guī)則適用于__weak修飾符和__autoreleasing修飾符)

*** 通過(guò)__strong修飾符使ARC有效遵循了Objective-C內(nèi)存管理的思考方式 ***

  1. “自己生成的對(duì)象,自己持有”和“非自己生成的對(duì)象槽地,自己也能持有”只需通過(guò)對(duì)帶__strong修飾符的變量賦值便可達(dá)成
  2. 通過(guò)廢棄帶__strong修飾符的變量(變量作用域結(jié)束或是成員變量所屬對(duì)象廢棄)或者對(duì)變量賦值迁沫,都可以做到”不再需要自己持有的對(duì)象時(shí)釋放“
  3. 由于不必再次鍵入release,所以”非自己持有的對(duì)象無(wú)法釋放“原本就不會(huì)執(zhí)行

__strong修飾符的不足

__strong修飾符無(wú)法解決引用計(jì)數(shù)式內(nèi)存管理中存在的問(wèn)題——循環(huán)引用捌蚊。循環(huán)引用容易發(fā)生內(nèi)存泄露(內(nèi)存泄露:應(yīng)當(dāng)廢棄的對(duì)象在超出其生存周期后繼續(xù)存在)集畅。

  • 類成員變量的循環(huán)引用:
Snip20160126_12.png
  • 自引用:
Snip20160126_13.png

*** __weak修飾符 ***

__weak修飾符提供弱引用。弱引用不能持有對(duì)象缅糟。

{
    id _weak obj = [[NSObject alloc] init];
}

實(shí)際編譯以上代碼挺智,編譯器會(huì)報(bào)錯(cuò),如下:

Snip20160126_14.png

解釋:將自己生成并持有的對(duì)象賦值給帶__weak修飾符的變量obj窗宦,變量obj會(huì)立即釋放生成的對(duì)象赦颇。
解決方式:將對(duì)象賦值給附有__strong修飾符的變量之后再賦值給附有__weak修飾符的變量二鳄,如下:

{
    id __strong obj0 = [[NSObject alloc] init];
    id __weak obj1 = obj0;
}

由于帶__weak修飾符的變量(弱引用)不持有對(duì)象,所以超出其變量作用域時(shí)媒怯,對(duì)象即被釋放订讼。

__weak修飾符的優(yōu)點(diǎn)

  • 可以避免發(fā)生循環(huán)引用


    Snip20160126_15.png
  • 在持有“對(duì)象”的弱引用時(shí),若該對(duì)象被廢棄扇苞,則此弱引用將自動(dòng)失效且處于nil被賦值的狀態(tài)(空弱引用)欺殿,如以下代碼:
id __weak obj1 = nil;

{
    id __strong obj0 = [[NSObject alloc] init];
    
    obj1 = obj0;  // obj1變量持有NSObject對(duì)象的弱引用
    
    NSLog(@“A : %@”, obj1);  
    // output A : <NSObject: 0x731e180>
}

NSLog(@“B : %@”, obj1; // output B : (null)
  • 通過(guò)檢查附有__weak修飾符的變量是否為nil,可以判斷被賦值的對(duì)象是否已廢棄
  • __weak修飾符只能用于iOS5以上及OS X Lion以上版本的應(yīng)用程序

*** __unsafe_unretained修飾符 ***

源代碼分析:

id __unsafe_unretained obj1 = nil;
{
    id __strong obj0 = [[NSObject alloc] init];
    
    obj1 = obj0; 
    // obj1變量即不持有對(duì)象的強(qiáng)引用也不持有弱引用
    
    NSLog(@"A: %@", obj1);
    // 輸出obj1變量表示的對(duì)象
    
}
/*
 * 因?yàn)閛bj0變量超出其作用域鳖敷,強(qiáng)引用失效祈餐,
 * 所以自動(dòng)釋放自己持有的對(duì)象
 * 因?yàn)閷?duì)象無(wú)持有者,所以廢棄該對(duì)象
 */

 NSLog(@"B: %@", obj1);
 /*
  * 輸出obj1變量表示的對(duì)象
  * 
  * obj1表示的對(duì)象已經(jīng)被廢棄(懸垂指針)哄陶!
  * 錯(cuò)誤訪問(wèn)!
  */
  • 附有 __unsafe_unretained修飾符的變量不屬于編譯器的內(nèi)存管理對(duì)象哺壶。
  • 附有__unsafe_unretained修飾符的變量同附有__weak修飾符的變量一樣屋吨,因?yàn)樽约荷刹⒊钟械膶?duì)象不能繼續(xù)為自己所有,所以生成的對(duì)象會(huì)立即被釋放山宾。
  • 訪問(wèn)了已經(jīng)被廢棄的對(duì)象至扰,只有在個(gè)別運(yùn)行情況下應(yīng)用程序才會(huì)崩潰。
  • 在使用__unsafe_unretained修飾符時(shí)资锰,賦值給附有__strong修飾符的變量時(shí)有必要確保被賦值的對(duì)象確實(shí)存在
  • 賦值給附有__unsafe_unretained修飾符變量的對(duì)象在通過(guò)該變量使用時(shí)敢课,如果沒有確保其確實(shí)存在,那么應(yīng)用程序就會(huì)崩潰

*** __autoreleasing修飾符 ***

  • 在ARC有效時(shí)绷杜,用@autoreleasepool塊替代NSAutoreleasePool類直秆,用附有_autoreleasing修飾符的變量替代autorelease方法,如下:


    Snip20160128_17.png
  • 不需要顯式地附加__autoreleasing修飾符鞭盟,因?yàn)榫幾g器會(huì)檢查方法名是否已a(bǔ)lloc/new/copy/mutableCopy方法開始圾结,如果不是則自動(dòng)將返回值的對(duì)象注冊(cè)到autoreleasePool。
@autoreleasePool{
    
    id __strong obj = [NSMutableArray array];
    
    /*
     * obj變量持有對(duì)象的強(qiáng)引用
     *
     * 并且該對(duì)象由編譯器判斷其方法名后齿诉,
     * 自動(dòng)注冊(cè)到autoreleasePool
     */
    
}/*
  * obj變量超出其作用域筝野,強(qiáng)引用失效
  * 所以自動(dòng)釋放自己持有的對(duì)象
  * 
  * 同時(shí),隨著@autoreleasePool塊的結(jié)束粤剧,
  * 注冊(cè)到autoreleasePool中的所有對(duì)象被自動(dòng)釋放
  * 
  * 因?yàn)閷?duì)象的所有者不存在歇竟,所以廢棄該對(duì)象
  */

  • 訪問(wèn)附有__weak修飾符的變量時(shí),實(shí)際上必定要訪問(wèn)注冊(cè)到autoreleasePool的對(duì)象抵恋。
  • id的指針或?qū)ο蟮闹羔樤跊]有顯式指定時(shí)會(huì)被附加上_autoreleasing修飾符焕议,如下:
指針 帶__autoreleasing修飾符
id的指針id *obj id __autoreleasing *obj
對(duì)象的指針NSObject **obj NSObject *__autoreleasing *obj
  • 為了得到詳細(xì)的錯(cuò)誤信息,經(jīng)常在方法的參數(shù)中傳遞NSError對(duì)象的指針馋记,而不是函數(shù)返回值号坡。
// 方法聲明
- (Bool)performOperationWithError:(NSError **)error;
// 等同于
- (Bool)performOperationWithError:(NSError *__autoreleasing *)error;

// 應(yīng)用
NSError *error = nil; 
Bool result = [obj performOperationWithError:&error];

// 上述源代碼經(jīng)過(guò)編譯器的轉(zhuǎn)化:
NSError __strong *error = nil;
NSError __autoreleasing *tmp = error;
Bool result = [obj performOperationWithError:&tmp];
error = tmp;

/*
 編譯器正是通過(guò)這種添加源代碼的方式使得原先的源代碼即不會(huì)編譯出錯(cuò)懊烤,也能在使用  參數(shù)取得對(duì)象時(shí),貫徹內(nèi)存管理的思考方式宽堆。
 */
  • 在顯式地指定__autoreleasing修飾符時(shí)腌紧,必須注意對(duì)象變量要為自動(dòng)變量(包括局部變量、函數(shù)以及方法參數(shù))

1.3.4 ARC的規(guī)則

  • 不能使用retain/release/retainCount/autorelease
  • 不能使用NSAllocateObject/NSDeallocateObject
  • 須遵守內(nèi)存管理的方法命名規(guī)則
  • 不要顯式調(diào)用dealloc
  • 使用@autoreleasePool替代NSAutoreleasePool
  • 不能使用區(qū)域(NSZone)
  • 對(duì)象型變量不能作為C語(yǔ)言結(jié)構(gòu)體(struct/union)的成員
  • 顯式轉(zhuǎn)換“id”和“void”

*** 須遵守內(nèi)存管理的方法命名規(guī)則 ***

在ARC有效時(shí)畜隶,用于對(duì)象生成/持有的方法除了alloc/new/copy/mutableCopy還要追加一條命名規(guī)則init壁肋。
該方法是實(shí)例方法,并且必須要返回對(duì)象籽慢。返回的對(duì)象應(yīng)為id類型或該方法聲明類的對(duì)象類型浸遗,或是該類的超類型或子類型。該返回對(duì)象并不注冊(cè)到autoreleasePool上箱亿□诵浚基本上只是對(duì)alloc方法返回值的對(duì)象進(jìn)行初始化處理并返回該對(duì)象。

*** 不要顯式調(diào)用dealloc ***

  • 對(duì)象被廢棄時(shí)届惋,不管ARC是否有效髓帽,都會(huì)調(diào)用對(duì)象的dealloc方法。在dealloc方法里記述廢棄對(duì)象時(shí)所需做的處理脑豹。
  • dealloc方法需要通過(guò)free來(lái)釋放留出的內(nèi)存郑藏。
  • dealloc方法在大多數(shù)情況下適用于刪除已注冊(cè)的代理或觀察者對(duì)象。

*** 對(duì)象型變量不能作為C語(yǔ)言結(jié)構(gòu)體(struct/union)的成員 ***

要把對(duì)象型變量加入到結(jié)構(gòu)體成員中時(shí)瘩欺,可強(qiáng)制轉(zhuǎn)換為void * 或是附加__unsafe_unretained修飾符

*** 顯式轉(zhuǎn)換“id”和“void” ***

  • id類型或?qū)ο箢愋妥兞抠x值給void *或者逆向賦值時(shí)都需要進(jìn)行特定的轉(zhuǎn)換必盖。如果只想單純地賦值,則可以使用"__bridge轉(zhuǎn)換"俱饿。如void *p = (__bridge void *)obj;
  • __bridge_retained轉(zhuǎn)換可使要轉(zhuǎn)換賦值的變量也持有所賦值的對(duì)象歌粥。與retain類似。
void *p = 0;
{
    id obj = [[NSObject alloc] init]; // 對(duì)象的retaidedCount : 1
    
    p = (__bridge_retained void *)obj; // 對(duì)象的retainedCount : 2
    
}
// 作用域結(jié)束時(shí)稍途,obj變量持有對(duì)象的強(qiáng)引用失效阁吝,所以釋放持有對(duì)象,但是由于__bridge_retained轉(zhuǎn)換使變量p看上去處于持有該對(duì)象的狀態(tài)械拍,因此該對(duì)象不會(huì)被廢棄
NSLog(@"class = %@", [(__bridge id)p class]);
  • __bridge_transfer突勇,被轉(zhuǎn)換的變量所持有的對(duì)象在該變量被賦值給轉(zhuǎn)換目標(biāo)變量后隨之釋放。與release類似坷虑。
  • 這些轉(zhuǎn)換多數(shù)使用在Objective-C對(duì)象和Core Foundation對(duì)象之間的相互變換中甲馋。

1.3.5 屬性

當(dāng)ARC有效時(shí),屬性聲明的屬性與所有權(quán)修飾符的對(duì)應(yīng)關(guān)系迄损,如下表:

屬性聲明的屬性 所有權(quán)修飾符
assign __unsafe_unretained修飾符
copy __strong修飾符(但是賦值的是被復(fù)制的對(duì)象)
retain __strong修飾符
strong __strong修飾符
unsafe_unretianed __unsafe_unretained修飾符
weak __weak修飾符

1.3.6 數(shù)組

  • __unsafe_unretained修飾符以外的__strong/__weak/__autoreleasing修飾符保證其指定的變量初始化為nil定躏。同樣地,附有__strong/__weak/__autoreleasing修飾符變量的數(shù)組也保證其初始化為nil。如下痊远,將附有__strong修飾符的變量作為靜態(tài)數(shù)組使用:id objs[10];

  • 將附有__strong修飾符的變量作為動(dòng)態(tài)數(shù)組使用時(shí)垮抗,根據(jù)不同的目的選擇使用NSMutableArray、NSMutableDictionary碧聪、NSMutableSet等Foundation框架的容器冒版。這些容器會(huì)恰當(dāng)?shù)爻钟凶芳拥膶?duì)象并為我們管理這些對(duì)象。

  • 在C語(yǔ)言的動(dòng)態(tài)數(shù)組使用附有__strong修飾符的變量逞姿,必須遵守一些事項(xiàng):

    1. 聲明動(dòng)態(tài)數(shù)組用指針,如id __strong *array = nil;由于不能保證附有__strong修飾符的id指針類型變量被初始化為nil辞嗡,需要自行賦值nil。
    2. 使用類名時(shí)如下滞造,NSObject *__strong *array = nil;
  • 使用calloc函數(shù)確保想分配的附有__strong修飾符變量的容量占有的內(nèi)存塊续室,如array = (id __strong *)calloc(entries, sizeof(id));

  • 在動(dòng)態(tài)數(shù)組中操作附有__strong修飾符的變量與靜態(tài)數(shù)組有很大差異,需要自己釋放所有的元素谒养。在用free函數(shù)廢棄數(shù)組用內(nèi)存塊前挺狰,需要先將nil賦值給所有元素,使得元素所賦值對(duì)象的強(qiáng)引用失效买窟,從而釋放那些對(duì)象她渴,再用free函數(shù)廢棄內(nèi)存塊。

  • 使用附有__weak修飾符變量的動(dòng)態(tài)數(shù)組與使用__strong修飾符相像蔑祟。

  • 在__autoreleasing修飾符的情況下,最好不要使用動(dòng)態(tài)數(shù)組沉唠。

  • 由于__unsafe_unretained修飾符在編譯器的內(nèi)存管理對(duì)象之外疆虚,所以它與void *類型一樣,只能作為C語(yǔ)言的指針類型來(lái)使用.

1.4 ARC的實(shí)現(xiàn)

ARC由以下工具满葛、庫(kù)來(lái)實(shí)現(xiàn):

  • clang(LLVM編譯器)3.0以上
  • objc4 Objective-C運(yùn)行時(shí)庫(kù)493.9以上

1.4.1 __strong修飾符

{
    id __strong obj = [[NSObject alloc] init];
}

以上源代碼可轉(zhuǎn)換為調(diào)用以下的函數(shù)径簿,

/* 編譯器的模擬代碼  */
id obj = objc_msgSend(NSObject, @selector(alloc));
objc_msgSend(obj, @selector(init));
objc_release(obj);

總結(jié)

如上所示,*** 在ARC有效時(shí)不能使用release方法的緣故是編譯器會(huì)自動(dòng)插入release嘀韧。***

NSMutableArray類的array類方法的調(diào)用如下:

{
    id __strong obj = [NSMutableArray array];
}

轉(zhuǎn)換后的源代碼是

/* 編譯器的模擬代碼  */
id obj = objc_msgSend(NSMutableArray, @selector(array));
objc_retainAutoreleasedReturnValue(obj);
objc_release(obj);

其中篇亭,NSMutableArray類的array類方法:

+ (id) array
{
    return [[NSMutableArray alloc] init];
}

轉(zhuǎn)換后的源代碼是

/* 編譯器的模擬代碼  */
+ (id) array 
{
    id obj = objc_msgSend(NSMutableArray, @selector(alloc));
    objc_msgSend(obj, @selector(init));
    return objc_autoreleaseReturnValue(obj);
}

總結(jié)

如上所示,*** objc_retainAutoreleasedReturnValue函數(shù)和objc_autoreleaseReturnValue函數(shù)的協(xié)作锄贷,可以不將對(duì)象注冊(cè)到autoreleasePool中而直接傳遞译蒂,這一過(guò)程達(dá)到了最優(yōu)化。***
如圖所示:


Snip20160128_19.png

關(guān)鍵知識(shí)點(diǎn):

  • objc_autoreleaseReturnValue函數(shù)用于alloc/new/copy/mutableCopy方法以外的NSMutableArray類的array類方法等返回對(duì)象的實(shí)現(xiàn)上谊却。

  • objc_autoreleaseReturnValue函數(shù)與objc_autorelease函數(shù)不同柔昼,一般不僅限于注冊(cè)對(duì)象到autoreleasePool中。

  • objc_retainAutoreleasedReturnValue函數(shù)主要用于最優(yōu)化程序運(yùn)行形导。即干茉,它是用于自己持有(retain)對(duì)象的函數(shù)唠梨,但它持有的對(duì)象應(yīng)為返回注冊(cè)在autoreleasePool中對(duì)象的方法或是函數(shù)的返回值棵譬。

  • objc_retainAutoreleasedReturnValue函數(shù)與objc_retain函數(shù)不同乙嘀,它即時(shí)不注冊(cè)到autoreleasePool而返回對(duì)象末购,也能夠正確地獲取對(duì)象。

  • 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)用方嘉冒。

1.4.2 __weak修飾符

  • 若附有__weak修飾符的變量所引用的對(duì)象被廢棄曹货,則將nil賦值給該變量。
  • 使用附有__weak修飾符的變量讳推,即是使用注冊(cè)到autoreleasePool中的對(duì)象顶籽。

假設(shè)obj附有__strong修飾符且對(duì)象被賦值

{   
    id __weak obj1 = obj;
}

轉(zhuǎn)換后的源代碼是

/* 編譯器的模擬代碼 */
id obj1;
objc_initWeak(&obj1, obj);
objc_destroyWeak(&obj1);

其中,objc_initWeak函數(shù)將附有__weak修飾符的變量初始化為0后银觅,會(huì)將賦值的對(duì)象作為參數(shù)調(diào)用objc_storeWeak函數(shù):

obj1 = 0;
objc_storeWeak(&obj1, obj);

objc_destroyWeak函數(shù)將0作為參數(shù)調(diào)用objc_storeWeak函數(shù):

objc_storeWeak(%obj1, 0);

即礼饱,轉(zhuǎn)換后的源代碼也可以是

/* 編譯器的模擬代碼 */
id obj1;
obj1 = 0;
objc_storeWeak(&obj1, obj);
objc_storeWeak(%obj1, 0);

總結(jié)

  • 通過(guò)objc_initWeak函數(shù)初始化附有__weak修飾符的變量,在變量作用域結(jié)束時(shí)通過(guò)objc_destroyWeak函數(shù)釋放該變量究驴。
  • objc_destroyWeak函數(shù)把第二參數(shù)的賦值對(duì)象的地址作為鍵值镊绪,將第一參數(shù)的附有__weak修飾符的變量的地址注冊(cè)到weak表中。如果第二參數(shù)為0洒忧,則把變量的地址從weak表中刪除蝴韭。

釋放對(duì)象,廢棄誰(shuí)都不持有的對(duì)象時(shí)熙侍,程序的動(dòng)作:

  1. objc_release
  2. 因?yàn)橐糜?jì)數(shù)為0所以執(zhí)行dealloc
  3. _objc_rootDealloc
  4. object_dispose
  5. objc_destructInstance
  6. objc_clear_deallocating

其中榄鉴,對(duì)象被廢棄時(shí)最后調(diào)用的objc_clear_deallocating函數(shù)的動(dòng)作如下:

  1. 從weak表中獲取廢棄對(duì)象的地址為鍵值的記錄
  2. 將包含在記錄中的所有附有__weak修飾符變量的地址,賦值為nil(釋放變量)
  3. 從weak表中刪除該記錄
  4. 從引用計(jì)數(shù)表中刪除廢棄對(duì)象的地址為鍵值的記錄(廢棄對(duì)象)

注意

  • 附有__weak修飾符的變量所引用的對(duì)象被廢棄時(shí)蛉抓,則將nil賦值給該變量庆尘。如果大量使用附有__weak修飾符的變量,則會(huì)消耗相應(yīng)的CPU資源巷送。最好是只在需要避免循環(huán)引用時(shí)使用__weak修飾符驶忌。
  • 將自己生成并持有的對(duì)象直接賦值給附有__weak修飾符的變量,編譯器會(huì)報(bào)錯(cuò)笑跛,如下:
{
    id __weak obj = [[NSObject alloc] init];
}

obj變量不能持有該對(duì)象付魔,這時(shí)會(huì)被釋放并被廢棄,引起編譯器的警告飞蹂。

Snip20160129_1.png

通過(guò)轉(zhuǎn)換后的源代碼解釋抒抬,

/* 編譯器的模擬代碼  */
id obj;
id tmp = objc_msgSend(NSObject, @selctor(alloc));
objc_msgSend(tmp, @selctor(init));
objc_initWeak(&obj, tmp);
objc_release(tmp); // 釋放該對(duì)象
objc_destroyWeak(&object); // 廢棄該對(duì)象

總結(jié)

  • 雖然自己生成并持有的對(duì)象通過(guò)objc_initWeak函數(shù)被賦值給附有__weak修飾符的變量中,但編譯器判斷其沒有持有者晤柄,故該對(duì)象立即通過(guò)objc_release函數(shù)被釋放和廢棄擦剑。
  • nil會(huì)被賦值給引用廢棄對(duì)象的附有__weak修飾符的變量中。

假設(shè)obj附有__strong修飾符且對(duì)象被賦值

{   
    id __weak obj1 = obj;
    NSLog(@"%@", obj1);
}

轉(zhuǎn)換后的源代碼是

/* 編譯器的模擬代碼 */
id obj1;
objc_initWeak(&obj1, obj);
id tmp = objc_loadWeakRetained(&obj1);
objc_autorelease(tmp);
NSLog(@"%@", tmp);
objc_destroyWeak(&obj1);

其中,與前面的被賦值時(shí)相比惠勒,在使用附有__weak修飾符變量的情形下赚抡,增加了對(duì)objc_loadWeakRetained函數(shù)和objc_autorelease函數(shù)的調(diào)用。這兩個(gè)函數(shù)的動(dòng)作如下:

  1. objc_loadWeakRetained函數(shù)取出附有__weak修飾符所引用的對(duì)象并retain纠屋。
  2. objc_autorelease函數(shù)將對(duì)象注冊(cè)到autoreleasepool中涂臣。

注意

  • 因?yàn)楦接衉_weak修飾符變量所引起的對(duì)象像這樣被注冊(cè)到autoreleasepool中,所以在@autoreleasepool塊結(jié)束之前都可以放心使用售担。
  • 如果大量地使用附有__weak修飾符的變量赁遗,注冊(cè)到autoreleasepool的對(duì)象也會(huì)大量地增加,因此在使用附有__weak修飾符的變量時(shí)族铆,最好先暫時(shí)賦值給附有__strong修飾符的變量后再使用岩四。如
{
   id __weak o = obj;
   id tmp = o;
   NSLog(@"1 %@", tmp);
   NSLog(@"2 %@", tmp);
   NSLog(@"3 %@", tmp);
}

1.4.3 __autoreleasing修飾符

將對(duì)象賦值給附有__autoreleasing修飾符的變量等同于ARC無(wú)效時(shí)調(diào)用對(duì)象的autorelease方法。

alloc/new/copy/mutableCopy方法群:

@autoreleasepool{
    id __autoreleasing obj = [[NSObject alloc] init]
}

轉(zhuǎn)換后的源代碼是

/* 編譯器模擬代碼  */
id pool = objc_autoreleasePoolPush();
id obj = objc_msgSend(NSObject, @selctor(alloc));
objc_msgSend(obj, @selctor(init));
objc_autorelease(obj); // 將對(duì)象添加到autoreleasepool中
objc_autoreleasePoolPop(pool);

NSMutableArray類的array類方法:

@autoreleasepool{
    id __autoreleasing obj = [NSMutableArray array];
}

轉(zhuǎn)換后的源代碼是

/* 編譯器的模擬代碼  */
id pool = objc_autoreleasePoolPush();
id obj = objc_msgSend(NSMutableArray, @selctor(array));
objc_retainAutoreleasedReturnValue(obj);//用于自己持有(retain)對(duì)象
objc_autorelease(obj); // 將對(duì)象添加到autoreleasepool中
objc_autoreleasePoolPop(pool);

1.4.4 引用計(jì)數(shù)

  • 由于弱引用并不持有對(duì)象哥攘,所以賦值給附有__weak修飾符的變量中也必定不會(huì)改變引用計(jì)數(shù)數(shù)值剖煌。
  • 通過(guò)__autoreleasing修飾符向autoreleasepool注冊(cè)時(shí),引用計(jì)數(shù)數(shù)值會(huì)加1逝淹,但是@autoreleasepool塊結(jié)束時(shí)會(huì)釋放已注冊(cè)的對(duì)象耕姊,引用計(jì)數(shù)數(shù)值會(huì)減1。
  • 不使用__autoreleasing修飾符栅葡,僅使用附有__weak修飾符聲明的變量也能將引用對(duì)象注冊(cè)到autoreleasepool中茉兰。
  • 不能完全信任_objc_rootRetainCount函數(shù)取得的數(shù)值。

后記

由于該書講解知識(shí)點(diǎn)并沒有完整的實(shí)例欣簇,所以還需要再找另外的書籍或者博客進(jìn)行練習(xí)邦邦。個(gè)人更偏向于書籍,精通Objective-C第4醉蚁、5、6章有相關(guān)內(nèi)存管理和ARC方面的講解和練習(xí)鬼店。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末网棍,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子妇智,更是在濱河造成了極大的恐慌滥玷,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,482評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件巍棱,死亡現(xiàn)場(chǎng)離奇詭異惑畴,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)航徙,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門如贷,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事杠袱∩性常” “怎么了?”我有些...
    開封第一講書人閱讀 152,762評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵楣富,是天一觀的道長(zhǎng)凿掂。 經(jīng)常有香客問(wèn)我,道長(zhǎng)纹蝴,這世上最難降的妖魔是什么庄萎? 我笑而不...
    開封第一講書人閱讀 55,273評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮塘安,結(jié)果婚禮上糠涛,老公的妹妹穿的比我還像新娘。我一直安慰自己耙旦,他們只是感情好脱羡,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,289評(píng)論 5 373
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著免都,像睡著了一般锉罐。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上绕娘,一...
    開封第一講書人閱讀 49,046評(píng)論 1 285
  • 那天脓规,我揣著相機(jī)與錄音,去河邊找鬼险领。 笑死侨舆,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的绢陌。 我是一名探鬼主播挨下,決...
    沈念sama閱讀 38,351評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼脐湾!你這毒婦竟也來(lái)了臭笆?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,988評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤秤掌,失蹤者是張志新(化名)和其女友劉穎愁铺,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體闻鉴,經(jīng)...
    沈念sama閱讀 43,476評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡茵乱,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,948評(píng)論 2 324
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了孟岛。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片瓶竭。...
    茶點(diǎn)故事閱讀 38,064評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡督勺,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出在验,到底是詐尸還是另有隱情玷氏,我是刑警寧澤,帶...
    沈念sama閱讀 33,712評(píng)論 4 323
  • 正文 年R本政府宣布腋舌,位于F島的核電站盏触,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏块饺。R本人自食惡果不足惜赞辩,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,261評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望授艰。 院中可真熱鬧辨嗽,春花似錦、人聲如沸淮腾。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,264評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)谷朝。三九已至洲押,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間圆凰,已是汗流浹背杈帐。 一陣腳步聲響...
    開封第一講書人閱讀 31,486評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留专钉,地道東北人挑童。 一個(gè)月前我還...
    沈念sama閱讀 45,511評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像跃须,于是被迫代替她去往敵國(guó)和親站叼。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,802評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容