Objective-C中如何實(shí)現(xiàn)ARC

這篇文章將為大家詳細(xì)講解有關(guān)Objective-C中如何實(shí)現(xiàn)ARC,小編覺得挺實(shí)用的,因此分享給大家做個(gè)參考,希望大家閱讀完這篇文章后可以有所收獲。

十余年專注成都網(wǎng)站制作,企業(yè)網(wǎng)站建設(shè),個(gè)人網(wǎng)站制作服務(wù),為大家分享網(wǎng)站制作知識(shí)、方案,網(wǎng)站設(shè)計(jì)流程、步驟,成功服務(wù)上千家企業(yè)。為您提供網(wǎng)站建設(shè),網(wǎng)站制作,網(wǎng)頁設(shè)計(jì)及定制高端網(wǎng)站建設(shè)服務(wù),專注于企業(yè)網(wǎng)站建設(shè),高端網(wǎng)頁制作,對石牌坊等多個(gè)方面,擁有豐富的網(wǎng)站營銷經(jīng)驗(yàn)。

前言

在ARC出現(xiàn)以前,程序員們只能靠retain/relese/autorelease來確保對象們恰好“堅(jiān)持”到被需要的那一刻。如果忘了retain,或者多次release某個(gè)對象,程序就會(huì)發(fā)生內(nèi)存泄漏的問題,甚至直接崩潰。

在Xcode 4.2中,除了語法檢查外,Apple的新LLVM編譯器還將內(nèi)存管理的苦差事接了過來,它會(huì)檢查代碼,決定何時(shí)釋放對象。Apple的文檔里是這么定義ARC的:

“自動(dòng)引用計(jì)數(shù)(ARC)是一個(gè)編譯器級(jí)的功能,它能簡化Cocoa應(yīng)用中對象生命周期管理(內(nèi)存管理)的流程。”

ARC使內(nèi)存管理在大部分時(shí)候變得如同小事一樁,但我們?nèi)砸跊Q定自己的類如何管理其它對象的引用時(shí)承擔(dān)一些責(zé)任。

蘋果的官方說明中稱,ARC是“由編譯器進(jìn)行內(nèi)存管理”的,但是實(shí)際上只有編譯其是無法完全勝任的,再次基礎(chǔ)上還需要Objective-C運(yùn)行時(shí)庫的協(xié)助。

也就是說,ARC由以下工具、庫來實(shí)現(xiàn)。

  • clang(LLVM編輯器)

  • objc4 Objective-C 運(yùn)行時(shí)庫

__strong 修飾符

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

~~本人是c/cpp小白,沒有編譯成功,沒看到匯編輸出TAT~~

以上代碼編譯器的模擬代碼:

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

如上所示,調(diào)用了2次objc_msgSend方法,變量的作用域結(jié)束時(shí)通過objc_release釋放對象。雖然ARC有效時(shí)不能使用release方法,但由此可知編譯器自動(dòng)插入了release。

使用alloc/new/copy/mutableCopy以外的方法時(shí):

{
 id __strong obj = [NSMutableArray array];
}

編譯器的模擬代碼如下:

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

其中的objc_retainAutoreleasedReturnValue函數(shù)主要用于優(yōu)化程序運(yùn)行,它用于自己持有(retain)對象的函數(shù),但它持有的對象應(yīng)為返回注冊在autoreleasepool中對象的方法,或是函數(shù)的返回值。在調(diào)用alloc/new/copy/mutableCopy以外的方法,由編譯器插入該函數(shù)。

與 objc_retainAutoreleaseReturnValue函數(shù)相對的函數(shù)為objc_autoreleaseReturnValue函數(shù)。它用于alloc/new/copy/mutableCopy方法以外的NSMutableArray類的array類方法等返回對象的實(shí)現(xiàn)上。

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

轉(zhuǎn)換后

+ (id) array
{
 id obj = objc_msgSend(NSArray,@selector(alloc));
 objc_msgSend(obj,@selector(init));
 return objc_autoreleaseReturnValue(obj);
}

返回注冊到autoreleasepool中對象的方法使用了objc_autoreleaseReturValue函數(shù)返回注冊到autoreleasepool中的對象。但是objc_autoreleaseReturValue函數(shù)同objc_autorelease函數(shù)不同,一般不僅限于注冊對象到autoreleasepool中。

objc_autoreleaseReturValue函數(shù)會(huì)檢查使用該函數(shù)的方法或函數(shù)調(diào)用方的執(zhí)行命令列表。如果方法或函數(shù)的調(diào)用方在調(diào)用了方法或函數(shù)后緊接著調(diào)用objc_retainAutoreleasedReturnValue()函數(shù),那么就不將返回的對象注冊到autoreleasepool中,而直接傳遞到方法或函數(shù)的調(diào)用方。objc_retainAutoreleasedReturnValue函數(shù)與objc_retain函數(shù)不同,它即便不注冊到autoreleasepool中而返回對象,也能夠正確地獲取對象。

通過objc_autoreleaseReturnValue函數(shù)和objc_retainAutoreleasedReturnValue函數(shù)的協(xié)作,可以不講對象注冊到autoreleasepool中而直接傳遞,這一過程達(dá)到了最優(yōu)化。

__weak 修飾符

  • 若附有__weak修飾符的變量所引用的對象被廢棄,則將nil賦值給該變量。

  • 使用附有__weak修飾符的變量,即是使用注冊到了autoreleasepool中的對象。

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

通過objc_initWeak函數(shù)初始化附有__weak修飾符的變量,在變量作用域結(jié)束時(shí)通過objc_destroyWeak函數(shù)釋放該變量。
如以下源碼所示,objc_initWeak函數(shù)將附有__weak修飾符的變量初始化為0后,會(huì)將賦值的對象作為參數(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);

即前面的源代碼和以下代碼相同:

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

objc_weakStore函數(shù)把第二參數(shù)的復(fù)制對象的地址作為鍵值,將第一參數(shù)的附有__weak修飾符的變量的地址注冊到weak表中,如果第二參數(shù)為0,則把變量的地址從weak表中刪除。

weak表與引用計(jì)數(shù)表相同,作為散列表被實(shí)現(xiàn)。如果使用weak表,將廢棄對象的地址作為鍵值進(jìn)行檢索,能高速地獲取對應(yīng)的附有__weak修飾符的變量的地址。另外,由于一個(gè)對象可以同時(shí)賦值給多個(gè)附有__weak修飾符的變量中,所以對于一個(gè)鍵值,可注冊多個(gè)變量的地址。

釋放對象時(shí),廢棄誰都不持有的對象,通過objc_release函數(shù)釋放。

  • objc_release

  • 因?yàn)橛?jì)數(shù)為0,所以執(zhí)行dealloc

  • _objc_rootDealloc

  • object_dispose

  • objc_destructInstanse

  • objc_clear_deallocating

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

  • 從weak表中獲取廢棄對象的地址為鍵值的記錄。

  • 將包含在記錄中的所有附有__weak修飾符變量的地址,賦值為nil

  • 從weak表中刪除該記錄。

  • 從引用計(jì)數(shù)表中刪除廢棄對象的地址作為鍵值的記錄。

根據(jù)以上步驟,前面說的如果附有__weak修飾符的變量所引用的對象被廢棄,則將nil賦值給該變量這一功能即被實(shí)現(xiàn)。由此可知,如果大量使用附有__weak修飾符的變量,則會(huì)消耗相應(yīng)的CPU資源,對此只在需要避免循環(huán)引用的時(shí)候使用__weak修飾符。

使用__weak修飾符時(shí),以下代碼會(huì)引起編譯器警告

{
 id __weak obj = [[NSObject alloc] init];
 NSLog(@"obj = %@",obj);
}

編譯結(jié)果如下:

Assigning retained object to weak variable; object will be released after assignment

編譯器模擬代碼如下:

id obj;
id temp = objc_msgSend(NSObject,@selector(alloc));
objc_msgSend(temp,@selector(init));
objc_initWeak(&obj,temp);
objc_release(temp);
objc_destroyWeak(&obj);

運(yùn)行結(jié)果如下:

2017-12-07 19:37:24.075939+0800 ImageOrientation[10963:3581164] obj = (null)

使用附有__weak修飾符的變量,即是使用注冊到autoreleasepool中的對象。

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

該代碼可以轉(zhuǎn)換為如下形式:

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

與賦值時(shí)相比,在使用附有__weak修飾符變量的情形下,增加了對objc_loadWeakRetained函數(shù)和objc_autorelease函數(shù)的調(diào)用。這些函數(shù)的動(dòng)作如下:

  • objc_loadWeakRetained函數(shù)取出附有__weak修飾符變量所引用的對象并retain

  • objc_autorelease函數(shù)將對象注冊到autoreleasepool中。

__autoreleasing 修飾符

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

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

模擬代碼如下:

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

alloc/new/copy/mutableCopy之外的方法實(shí)現(xiàn):

@autoreleasepool{
 id __autoreleasing obj = [NSMutableArray array];
}
/** 編譯器的模擬代碼 */
id pool = objc_autoreleasePoolPush();
id obj = objc_msgSend(NSMutableArray,@selector(array));
objc_retainAutorelesedReturnedValue(obj);
objc_autorelease(obj);
objc_autoreleasePoolPop(pool);

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

獲取引用計(jì)數(shù)的函數(shù)為CFGetRetainCount

例如:

{
 id __strong obj = [[NSObject alloc] init];
 NSLog(@"retainCount = %ld",CFGetRetainCount((__bridge CFTypeRef)obj));
}

結(jié)果為1

{
 id __strong obj = [[NSObject alloc] init];
 id __weak obj1 = obj;
 NSLog(@"retainCount = %ld",CFGetRetainCount((__bridge CFTypeRef)obj));
}

結(jié)果為2

{
 id __strong obj = [[NSObject alloc] init];
 id __autoreleaing obj1 = obj;
 NSLog(@"retainCount = %ld",CFGetRetainCount((__bridge CFTypeRef)obj));
}

結(jié)果為2

{
 id __strong obj = [[NSObject alloc] init];
 @autoreleasepool{
  id __autoreleaing obj1 = obj;
  NSLog(@"retainCount = %ld",CFGetRetainCount((__bridge CFTypeRef)obj));
}
 }
 NSLog(@"retainCount = %ld",CFGetRetainCount((__bridge CFTypeRef)obj));
}

結(jié)果為2和1

關(guān)于“Objective-C中如何實(shí)現(xiàn)ARC”這篇文章就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,使各位可以學(xué)到更多知識(shí),如果覺得文章不錯(cuò),請把它分享出去讓更多的人看到。

新聞標(biāo)題:Objective-C中如何實(shí)現(xiàn)ARC
本文URL:http://muchs.cn/article38/gdiesp.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供動(dòng)態(tài)網(wǎng)站、商城網(wǎng)站、品牌網(wǎng)站建設(shè)、靜態(tài)網(wǎng)站、軟件開發(fā)面包屑導(dǎo)航

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

h5響應(yīng)式網(wǎng)站建設(shè)