內(nèi)存管理 知識(shí)整理

前言

從我開(kāi)始學(xué)習(xí)iOS的時(shí)候浅侨,身邊的朋友、網(wǎng)上的博客都告訴我iOS的內(nèi)存管理是依靠引用計(jì)數(shù)的证膨,然后說(shuō)引用計(jì)數(shù)大于1則對(duì)象保存在內(nèi)存的堆中而引用計(jì)數(shù)等于0則對(duì)象銷(xiāo)毀如输。然后又說(shuō)在所謂的ARC時(shí)代,強(qiáng)指針指向一個(gè)對(duì)象央勒,則對(duì)象不銷(xiāo)毀;一個(gè)對(duì)象沒(méi)有任何一個(gè)強(qiáng)指針指向則銷(xiāo)毀....不见,最后,我想說(shuō)這些都很有道理的樣子崔步,但是稳吮,我還是不清楚為什么引用計(jì)數(shù)器為0為什么會(huì)被銷(xiāo)毀,為什么一個(gè)對(duì)象沒(méi)有強(qiáng)指針指向就會(huì)銷(xiāo)毀井濒,為什么在@property中一個(gè)OC對(duì)象要使用strong進(jìn)行修飾 .... 盖高。所以,在學(xué)習(xí)Objective-C高級(jí)編程:iOS與OS X多線程和內(nèi)存管理后眼虱,讓我明白了很多事情。以下是對(duì)于這本書(shū)里面知識(shí)的總結(jié)性內(nèi)容捏悬,如果要詳細(xì)了解,請(qǐng)閱讀該書(shū)籍过牙。

注意:下面的內(nèi)容是適合于已經(jīng)對(duì)于iOS內(nèi)存管理有一定了解的程序員

內(nèi)存管理的思考方式

自己生成的對(duì)象,自己持有

非自己生成的對(duì)象舶赔,自己也能持有

不再需要自己持有對(duì)象時(shí)釋放

非自己持有的對(duì)象無(wú)法釋放

1) 自己生成的對(duì)象,自己持有

在iOS內(nèi)存管理中有四個(gè)關(guān)鍵字疚鲤,alloc集歇、new桶略、copy、mutableCopy诲宇,自身使用這些關(guān)鍵字產(chǎn)生對(duì)象,那么自身就持有了對(duì)象

// 使用了alloc分配了內(nèi)存际歼,obj指向了對(duì)象,該對(duì)象本身引用計(jì)數(shù)為1,不需要retainidobj = [[NSObjectalloc] init];// 使用了new分配了內(nèi)存,objc指向了對(duì)象姑蓝,該對(duì)象本身引用計(jì)數(shù)為1鹅心,不需要retainidobj = [NSObjectnew];

2) 非自己生成的對(duì)象,自己也能持有

// NSMutableArray通過(guò)類(lèi)方法array產(chǎn)生了對(duì)象(并沒(méi)有使用alloc它掂、new巴帮、copy、mutableCopt來(lái)產(chǎn)生對(duì)象),因此該對(duì)象不屬于obj自身產(chǎn)生的// 因此虐秋,需要使用retain方法讓對(duì)象計(jì)數(shù)器+1,從而obj可以持有該對(duì)象(盡管該對(duì)象不是他產(chǎn)生的)idobj = [NSMutableArrayarray];? ? [objretain];

3) 不再需要自己持有對(duì)象時(shí)釋放

idobj = [NSMutableArrayarray];? ? ? [objretain];// 當(dāng)obj不在需要持有的對(duì)象榕茧,那么,obj應(yīng)該發(fā)送release消息[obj release];

4) 無(wú)法釋放非自己持有的對(duì)象

// 1. 釋放一個(gè)已經(jīng)釋放的對(duì)象id obj = [[NSObject alloc] init];// 已經(jīng)釋放對(duì)象[objrelease];// 釋放了對(duì)象還進(jìn)行釋放[objrelease];// 2. 釋放一個(gè)不屬于自己的對(duì)象id obj1 = [obj object];// obj1沒(méi)有進(jìn)行retain操作而進(jìn)行release操作客给,使得obj持有對(duì)象釋放用押,造成了野指針錯(cuò)誤[obj1release];

如上為iOS進(jìn)行內(nèi)存管理的四種思考方式(記住不論是ARC還是MRC都遵循該思考方式,只是ARC時(shí)代這些工作讓編譯器做了)

引用計(jì)數(shù)器討論

蘋(píng)果對(duì)于引用計(jì)數(shù)的管理是通過(guò)一張引用計(jì)數(shù)表進(jìn)行管理的

引用計(jì)數(shù)表.png

我們平常在操作對(duì)象的引用計(jì)數(shù)器時(shí)靶剑,其實(shí)就是對(duì)這個(gè)引用計(jì)數(shù)表進(jìn)行操作,在獲取到該表的地址以及相應(yīng)對(duì)象的內(nèi)存地址蜻拨,就可以通過(guò)對(duì)象的內(nèi)存從該表中進(jìn)行索引獲取到相應(yīng)的引用計(jì)數(shù)值,然后根據(jù)用戶的操作來(lái)返回計(jì)時(shí)器桩引、計(jì)時(shí)器加1缎讼、計(jì)時(shí)器減1,下面就深入討論retain、release坑匠、alloc血崭、dealloc具體怎么操作該引用計(jì)數(shù)表

alloc

當(dāng)我們調(diào)用alloc函數(shù)時(shí)我們進(jìn)一步會(huì)調(diào)用allocWithZone方法

idobj = [[NSObjectalloc] init];? ? + (id)alloc {return[selfallocWithZone:NSDefaultMallocZone()];? ? }? ? + (id)allocWithZone:(NSZone*)z {returnNSAllocateObject(self,0,z);? ? }

調(diào)用NSAllocateObject函數(shù)對(duì)內(nèi)存進(jìn)行分配

retain、release、retainCount

該書(shū)籍對(duì)于這三個(gè)函數(shù)調(diào)用先是使用GNUstep(一個(gè)Cocoa框架的互換框架夹纫,功能類(lèi)似)進(jìn)行講解咽瓷,后來(lái)又講解了蘋(píng)果對(duì)于引用計(jì)數(shù)的實(shí)現(xiàn)。在這里我們就討論蘋(píng)果的實(shí)現(xiàn)了舰讹。

調(diào)用retain茅姜、release、retainCount時(shí)函數(shù)調(diào)用順序:

retain月匣、retainCount钻洒、release函數(shù)調(diào)用順序.png

如下所示,調(diào)用各個(gè)函數(shù)時(shí)會(huì)調(diào)用__CFDoExternRefOperation函數(shù)桶错,該函數(shù)包含于CFRuntime.c中航唆,該函數(shù)簡(jiǎn)化代碼如下:

- (NSUInteger)retainCount {return(NSUInteger)__CFDoExternRefOperation(OPERATION_retainCount,self);}- (id)retain{return(id)__CFDoExternRefOperation(OPERATION_retain,self);}- (void)release {return__CFDoExternRefOperation(OPERATION_release,self);}

int__CFDoExternRefOperation(uintptr_r op,id obj) {? ? ? ? CFBasicHashRef table = 取得對(duì)象對(duì)應(yīng)的散列表(obj);intcount;switch(op) {caseOPERATION_retainCount:count= CFBasicHashGetCountOfKey(table,obj);returncount;caseOPERATION_retain:? ? ? ? ? ? ? ? CFBasicHashAddValue(table,obj);returnobj;caseOPERATION_release:count= CFBasicHashRemoveValue(table,obj):return0==count;? ? ? ? }? ? }

代碼如上所示胀蛮,可以想象蘋(píng)果就是使用類(lèi)似于上述的引用計(jì)數(shù)表來(lái)管理內(nèi)存院刁,也就是說(shuō)我們?cè)谡{(diào)用retain、retainCount粪狼、release時(shí)首先調(diào)用__CFDoExternRefOperation進(jìn)而獲取到引用技術(shù)表的內(nèi)存地址以及本對(duì)象的內(nèi)存地址退腥,然后根據(jù)對(duì)象的內(nèi)存地址在表中查詢獲取到引用計(jì)數(shù)值。

若是retain就加1

若是retainCount就直接返回值再榄,

若是release則減1而且在CFBasicHashRemoveValue中將引用計(jì)數(shù)減少到0時(shí)會(huì)調(diào)用dealloc狡刘,從而調(diào)用NDDeallocateObject函數(shù)、free函數(shù)將對(duì)象所在內(nèi)存釋放

以上就是在討論蘋(píng)果對(duì)于引用計(jì)數(shù)的管理方法困鸥,對(duì)于GNUStep辦法請(qǐng)自行查閱書(shū)籍

autorelease

作用:將對(duì)象放入自動(dòng)釋放池中嗅蔬,當(dāng)自從釋放池銷(xiāo)毀時(shí)對(duì)自動(dòng)釋放池中的對(duì)象都進(jìn)行一次release操作

書(shū)寫(xiě)形式:

NSAutoreleasePool *pool =[[NSAutoreleasePool alloc]init];? ? id obj =[[NSObject alloc]init];[obj autorelease];[pool drain];

對(duì)于autorelease的實(shí)現(xiàn)方式,書(shū)籍也對(duì)比了GNUSetp與蘋(píng)果實(shí)現(xiàn)的方式疾就,現(xiàn)在通過(guò)GNUStep源代碼來(lái)理解蘋(píng)果的實(shí)現(xiàn)

1) GNUStep實(shí)現(xiàn)

id obj =[[NSObject alloc]init];[obj autorelease];

- (id)autorelease {? ? ? ? [NSAutoreleasePooladdObject:self];? ? }

+ (void)addObject:(id)anObject {NSAutoreleasePool*pool = 取得正在使用的Pool對(duì)象;if(pool !=nil) {? ? ? ? ? ? [pool addObject:anObject];? ? ? ? }else{NSLog(@"NSAutoreleasePool非存在狀態(tài)下使用Pool對(duì)象");? ? ? ? }? ? }

- (void)addObject:(id)anObject {? ? ? ? [arrayaddObject:anObject];? ? }

從上面可以看出澜术,自動(dòng)釋放池就是通過(guò)數(shù)組完成的,我們?cè)谡{(diào)用autorelease時(shí)最終就是將本對(duì)象添加到當(dāng)前自動(dòng)釋放池的數(shù)組

而針對(duì)于自動(dòng)釋放池銷(xiāo)毀時(shí)對(duì)數(shù)組中的進(jìn)行一次release操作猬腰,見(jiàn)下面

NSAutoreleasePool *pool =[[NSAutoreleasePool alloc]init];? ? ...? ? // 當(dāng)自動(dòng)釋放池銷(xiāo)毀時(shí)[pool drain];

- (void)drain {? ? ? ? [self dealloc];? ? }? ? - (void)dealloc {? ? ? ? [self emptyPool];? ? ? ? [arrayrelease];? ? }? ? - (void)emptyPool {for(id obj inarray) {? ? ? ? ? ? [objrelease];? ? ? ? }? ? }

2) 蘋(píng)果的實(shí)現(xiàn)

classAutoreleasePoolPage? ? {staticinlinevoid*push(){? ? ? ? ? ? 相當(dāng)于生成或持有NSAutoreleasePool類(lèi)對(duì)象? ? ? ? }staticinlinevoid*pop(void*token){? ? ? ? ? ? 相當(dāng)于廢棄NSAutoreleasePool類(lèi)對(duì)象? ? ? ? ? ? releaseAll();? ? ? ? }staticinlineidautorelease(id obj){? ? ? ? ? ? 相當(dāng)于NSAutoreleasePool類(lèi)的addObject類(lèi)方法? ? ? ? ? ? ? AutoreleasePoolPage *autoreleasePoolPage = 取得正在使用的AutoreleasePoolPage實(shí)例;? ? ? ? ? ? autoreleasePoolPage->add(obj);? ? ? ? }id *add(id obj){? ? ? ? ? ? 將對(duì)象追加到內(nèi)部數(shù)組中? ? ? ? }voidreleaseAll(){? ? ? ? ? ? 調(diào)用內(nèi)部數(shù)組中對(duì)象的release實(shí)例方法? ? ? ? }? ? };void*objc_autoreleasePoolPush(void){returnAutoreleasePoolPage::push();? ? }voidobjc_autoreleasePoolPage(void*ctxt){? ? ? ? AutoreleasePoolPage::pop(ctxt);? ? }id *objc_autorelease(id obj){returnAutoreleasePoolPage::autorelease(obj);? ? }

如上所示鸟废,蘋(píng)果內(nèi)部使用了類(lèi)似于GNUStep中的思想,將對(duì)象添加進(jìn)數(shù)組進(jìn)行管理

ARC中內(nèi)存管理方式

介紹

關(guān)于這部分的內(nèi)存姑荷,作者是分了兩部分進(jìn)行討論,第一部分介紹ARC管理所需要的關(guān)鍵字strong 、weak曲饱、unsafe_unretained趴拧、autoreleasing的作用;第二部分介紹了ARC針對(duì)于這些關(guān)

鍵字的具體內(nèi)管管理實(shí)現(xiàn)方式懈费。下面我們就綜合兩部分的內(nèi)容進(jìn)行一次討論

蘋(píng)果官方文檔說(shuō)ARC是有"編譯器自行進(jìn)行管理",但事實(shí)上僅僅是編譯器是不夠计露,需要滿足下面啷個(gè)條件

clang(LLVM編譯器)3.0以上

objc4 Objective-C運(yùn)行時(shí)庫(kù)493.9以上

__strong

作用

id__strongobj = [[NSObjectalloc]init];

如上代碼,表示obj這個(gè)強(qiáng)指針指向NSObject對(duì)象,且NSObject對(duì)象的引用計(jì)數(shù)為1

id__strongobj1 = obj;

如上代碼薄坏,表示obj1這個(gè)強(qiáng)指針與obj指針指向同一個(gè)NSObject對(duì)象趋厉,且NSObject對(duì)象的引用計(jì)數(shù)為2

id__strongobj = [NSMutableArrayarray];

如上代碼,表示obj這個(gè)強(qiáng)指針指向的NSMutableArray對(duì)象的引用計(jì)數(shù)為1

綜上所示胶坠,當(dāng)一個(gè)對(duì)象被強(qiáng)指針指向則引用計(jì)數(shù)就加1君账,否則,該對(duì)象沒(méi)有一個(gè)強(qiáng)指針指向則自動(dòng)釋放內(nèi)存

那么問(wèn)題來(lái)了沈善,為什么一個(gè)對(duì)象被強(qiáng)指針指向引用計(jì)數(shù)就加1呢? 為什么分配在堆里面的對(duì)象內(nèi)存能夠自動(dòng)釋放內(nèi)存?

原理

第一種情況: 對(duì)象是通過(guò)alloc乡数、new、copy闻牡、multyCopy來(lái)分配內(nèi)存的

id__strongobj = [[NSObjectalloc] init];

當(dāng)使用alloc净赴、new、copy罩润、multyCopt進(jìn)行對(duì)象內(nèi)存分配時(shí),強(qiáng)指針直接指向一個(gè)引用計(jì)數(shù)為1的對(duì)象玖翅,在編譯器作用下,上述代碼會(huì)轉(zhuǎn)換成以下代碼

id obj = objc_msgSend(NSObject,@selector(alloc));? ? objc_msgSend(obj,@selector(init));// 當(dāng)讓這個(gè)代碼會(huì)在合適的時(shí)候被調(diào)用割以,不是馬上調(diào)用objc_release(obj);

第二種情況: 對(duì)象不是自身生成金度,但是自身持有(一般這樣的對(duì)象是通過(guò)除alloc、new严沥、copy猜极、multyCopy外方法產(chǎn)生的)

id__strongobj = [NSMutableArrayarray];

在這種情況下,obj也指向一個(gè)引用計(jì)數(shù)為1的對(duì)象內(nèi)存,其在編譯器下轉(zhuǎn)換的代碼如下:

idobj = objc_msgSend(NSMutableArray,@selector(array));// 代替我們調(diào)用retain方法,使得obj可以持有該對(duì)象objc_retainAutoreleasedReturnValue(obj);? ? objc_release(obj);

從而使得obj指向了一個(gè)引用計(jì)數(shù)為1的對(duì)象, 不過(guò)消玄,objc_retainAutoreleaseReturnValue有一個(gè)成對(duì)的函數(shù)objc_autoreleaseReturnValue跟伏,這兩個(gè)函數(shù)可以用于最優(yōu)化程序的運(yùn)行

如下代碼:

+ (id)array? ? {return[[NSMutableArrayalloc] init];? ? }

代碼轉(zhuǎn)換如下:

+ (id)array? ? {? ? ? ? id obj = objc_msgSend(NSMutableArray,@selector(alloc));? ? ? ? objc_msgSend(obj,@selector(init));// 代替我們調(diào)用了autorelease方法returnobjc_autoreleaseReturnValue(obj);? ? }

在轉(zhuǎn)換后的代碼,我們可以看見(jiàn)調(diào)用了objc_autoreleaseReturnValue函數(shù)且這個(gè)函數(shù)會(huì)返回注冊(cè)到自動(dòng)釋放池的對(duì)象翩瓜,但是受扳,這個(gè)函數(shù)有個(gè)特點(diǎn),它會(huì)查看調(diào)用方的命令執(zhí)行列表奥溺,如果發(fā)現(xiàn)接

下來(lái)會(huì)調(diào)用objc_retainAutoreleasedReturnValue則不會(huì)返回注冊(cè)到自動(dòng)釋放池的對(duì)象而僅僅返回一個(gè)對(duì)象而已辞色。

兩者的關(guān)系圖如下:

關(guān)系圖.png

通過(guò)這些,我們就可以通知為什么強(qiáng)指針指向一個(gè)對(duì)象浮定,這個(gè)對(duì)象的引用計(jì)數(shù)就加1

__weak

作用

id__weakobj = [[NSObjectalloc] init];

根據(jù)我們的知識(shí)相满,可以知道NSObject對(duì)象在生成之后立馬就會(huì)被釋放,其主要原因是weak修飾的指針沒(méi)有引起對(duì)象內(nèi)部的引用計(jì)數(shù)器的變化

因此桦卒,weak修飾的指針常用于打破循環(huán)引用或者修飾UI控件立美,關(guān)于__weak修飾的指針引用場(chǎng)景這里不敘述,下面主要介紹其原理

原理

我們知道弱指針有兩個(gè)作用:一. 修飾的指針不會(huì)引起指向的對(duì)象的引用計(jì)數(shù)器變化 二. 當(dāng)指向的對(duì)象被銷(xiāo)毀時(shí)方灾,弱指針全部置為nil, 那么除了這些之外建蹄,我們還有一個(gè)要說(shuō)的就是碌更,為什么我們

在程序中不能頻繁的使用weak呢?

1) 為什么弱指針不會(huì)引起指向的對(duì)象的引用計(jì)數(shù)器發(fā)生變化

id__weakobj = [[NSObjectalloc] init];

編譯器轉(zhuǎn)換后的代碼如下:

id obj;id tmp = objc_msgSend(NSObject,@selector(alloc));objc_msgSend(tmp,@selector(init));objc_initweak(&obj,tmp);objc_release(tmp);objc_destroyWeak(&object);

對(duì)于__weak內(nèi)存管理也借助了類(lèi)似于引用計(jì)數(shù)表的表洞慎,它通過(guò)對(duì)象的內(nèi)存地址做為key痛单,而對(duì)應(yīng)的指針作為value進(jìn)行管理,在上述代碼中objc_initweak就是完成這部分操作劲腿,而objc_destroyWeak

則是銷(xiāo)毀該對(duì)象對(duì)應(yīng)的value旭绒。所以,weak在修飾只是讓weak表增加了記錄沒(méi)有引起引用計(jì)數(shù)表的變化

2) 當(dāng)弱指針指向的對(duì)象唄銷(xiāo)毀時(shí)焦人,弱指針怎么才能自動(dòng)置為nil? 為什么我們?cè)诔绦蛑胁荒茴l繁使用weak呢

對(duì)象通過(guò)objc_release釋放對(duì)象內(nèi)存的動(dòng)作如下:

objc_release

因?yàn)橐糜?jì)數(shù)為0所以執(zhí)行dealloc

_objc_rootDealloc

objc_dispose

objc_destructInstance

objc_clear_deallocating

而在對(duì)象被廢棄時(shí)最后調(diào)用了objc_clear_deallocating挥吵,該函數(shù)的動(dòng)作如下:

1) 從weak表中獲取已廢棄對(duì)象內(nèi)存地址對(duì)應(yīng)的所有記錄

2)將已廢棄對(duì)象內(nèi)存地址對(duì)應(yīng)的記錄中所有以weak修飾的變量都置為nil

3)從weak表刪除已廢棄對(duì)象內(nèi)存地址對(duì)應(yīng)的記錄

4)根據(jù)已廢棄對(duì)象內(nèi)存地址從引用計(jì)數(shù)表中找到對(duì)應(yīng)記錄刪除

據(jù)此可以解釋為什么對(duì)象被銷(xiāo)毀時(shí)對(duì)應(yīng)的weak指針變量全部都置為nil,同時(shí)花椭,也看出來(lái)銷(xiāo)毀weak步驟較多忽匈,如果大量使用weak的話會(huì)增加CPU的負(fù)荷

而不建議大量使用weak,還有一個(gè)原因看下面的代碼:

id__weakobj1 = obj;NSLog(@"obj2-%@",obj1);

編譯器轉(zhuǎn)換上述代碼如下:

id obj1;? ? objc_initweak(&obj1,obj);// 從weak表中獲取附有__weak修飾符變量所引用的對(duì)象并retainid tmp = objc_loadWeakRetained(&obj1);// 將對(duì)象放入自動(dòng)釋放池objc_autorelease(tmp);? ? NSLog(@"%@",tmp);? ? objc_destroyWeak(&obj1);

據(jù)此當(dāng)我們?cè)L問(wèn)weak修飾指針指向的對(duì)象時(shí)矿辽,實(shí)際上是訪問(wèn)注冊(cè)到自動(dòng)釋放池的對(duì)象丹允。因此,如果大量使用weak的話嗦锐,在我們?nèi)ピL問(wèn)weak修飾的對(duì)象時(shí)嫌松,會(huì)有大量對(duì)象注冊(cè)到自動(dòng)釋放池,這會(huì)影響程

序的性能沪曙。推薦方案 : 要訪問(wèn)weak修飾的變量時(shí)奕污,先將其賦給一個(gè)strong變量,然后進(jìn)行訪問(wèn)

最后一個(gè)問(wèn)題: 為什么訪問(wèn)weak修飾的對(duì)象就會(huì)訪問(wèn)注冊(cè)到自動(dòng)釋放池的對(duì)象呢?

因?yàn)閣eak不會(huì)引起對(duì)象的引用計(jì)數(shù)器變化液走,因此碳默,該對(duì)象在運(yùn)行過(guò)程中很有可能會(huì)被釋放。所以缘眶,需要將對(duì)象注冊(cè)到自動(dòng)釋放池中并在自動(dòng)釋放池銷(xiāo)毀時(shí)釋放對(duì)象占用的內(nèi)存嘱根。

__unsafe_unretained

作用

unsafe_unretained作用需要和weak進(jìn)行對(duì)比,它也不會(huì)引起對(duì)象的內(nèi)部引用計(jì)數(shù)器的變化巷懈,但是该抒,當(dāng)其指向的對(duì)象被銷(xiāo)毀時(shí)unsafr_unretained修飾的指針不會(huì)置為nil。而且一般__unsafe_unretained就和它的名字一樣是不安全顶燕,它不納入ARC的內(nèi)存管理

__autoreleasing

作用

ARC無(wú)效

NSAutoreleasePool *pool =[[NSAutoreleasePool alloc]init];? ? id obj =[[NSObject alloc]init];[obj autorelease];[pool drain];

ARC有效*

id __autoreleasing obj1 = obj;

如上所示凑保,通過(guò)__autoreleasing修飾符就完成了ARC無(wú)效時(shí)一樣的功能

當(dāng)然,在某一些情況下我們不通過(guò)顯式指定__autoreleasing關(guān)鍵字就可以完成自動(dòng)注冊(cè)到自動(dòng)釋放池的功能涌攻,例如以下情況

第一種:

@autoeleasepool {// 如果看了上面__strong的原理欧引,就知道實(shí)際上對(duì)象已經(jīng)注冊(cè)到自動(dòng)釋放池里面了id__strongobj = [NSMutableArrayarray];? ? }

第二種:

訪問(wèn)__weak修飾的對(duì)象時(shí),對(duì)象就被注冊(cè)到了自動(dòng)釋放池

第三種:

以下形式的默認(rèn)修飾符是__autorelease

id *obj;

NSObject **obj;

同時(shí)恳谎,也引出一個(gè)問(wèn)題: 為什么在@property中OC對(duì)象使用strong而基本數(shù)據(jù)類(lèi)型使用assign芝此?

屬性默認(rèn)修飾符.png

從表中可以推斷出憋肖,在ARC在OC對(duì)象的默認(rèn)修飾符是strong,因此婚苹,在@property中使用strong

而基本數(shù)據(jù)類(lèi)型是不納入到ARC內(nèi)存管理中的岸更,unsafe_unretained也不歸ARC管,因此膊升,使用assign對(duì)基本數(shù)據(jù)類(lèi)型進(jìn)行修飾

原理 ```objc @autoreleasepool {

id __autoreleasing obj =[[NSObject alloc]init];}

代碼轉(zhuǎn)換如下:? ```objc? ? id pool = objc_autoreleasePoolPush();id obj = objc_msgSend(NSObject,@selector(alloc));objc_msgSend(obj,@selector(init));objc_autorelease(obj);objc_autoreleasePoolPop(pool);

@autoreleasepool{id__autoreleasing obj = [NSMutableArrayarray];? ? }

代碼轉(zhuǎn)換如下:

id pool = objc_autoreleasePoolPush();id obj = objc_msgSend(NSMutableArray,@selector(array));objc_retainAutoreleasedReturnValue(obj);objc_autorelease(obk);objc_autoreleasePoolPop(pool);

上述代碼坐慰,代表的就是自身生成并持有對(duì)象、自身不生成但也持有對(duì)象的兩種__autorelease內(nèi)存管理情況

ARC規(guī)則

不能使用retain用僧、release结胀、retainCount、autorelease方法(如果ARC下使用會(huì)出現(xiàn)編譯錯(cuò)誤)

不能使用NSAllocateObject责循、NSDeallocateObject函數(shù)(如果ARC下使用會(huì)出現(xiàn)編譯錯(cuò)誤)

不要顯式調(diào)用dealloc(ARC下糟港,顯式調(diào)用dealloc并在代碼中書(shū)寫(xiě)[super dealloc]也會(huì)出現(xiàn)編譯錯(cuò)誤)

使用@autoreleasepool塊代替NSAutoreleasePool

@autoreleasepool{}塊相比較NSAutoreleasePool而言顯得代碼更加整潔、層次性強(qiáng)院仿,而且@autoreleasepool代碼快哉ARC或者非ARC下都是可以使用的

需遵守內(nèi)存管理命名規(guī)則

1) alloc秸抚、new、copy歹垫、mutableCopy等以這些名字開(kāi)頭的方法都應(yīng)當(dāng)返回調(diào)用方能夠持有的對(duì)象2)init開(kāi)頭的方法必須是實(shí)例方法并且要返回對(duì)象剥汤,返回值要是id或者該方法對(duì)應(yīng)類(lèi)的對(duì)象類(lèi)似或者其超類(lèi)或者其子類(lèi)。另外排惨,init開(kāi)頭的方法也僅僅用作對(duì)對(duì)象進(jìn)行初始化操作

不能使用區(qū)域(NSZone)

區(qū)域是以前為了高效利用內(nèi)存的使用率而設(shè)計(jì)的吭敢,但是,目前來(lái)說(shuō)ARC下的模式已經(jīng)能夠有效利用內(nèi)存暮芭,區(qū)域在ARC下還是非ARC下都已經(jīng)被單純的忽略

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

OC對(duì)象型變量如果成為了C語(yǔ)言結(jié)構(gòu)體的成員鹿驼,那么,ARC不能掌握該對(duì)象的生命周期從而有效管理內(nèi)存辕宏,因此畜晰,不能這樣使用。

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

非ARC下:idobj = [[NSObjectalloc] init];void*p = obj;? ? 這樣的代碼是可行的瑞筐,id和void*可以方便得自由轉(zhuǎn)化 凄鼻,但是,在ARC下是不一樣的? ? ARC下id和void*有三個(gè)轉(zhuǎn)換的關(guān)鍵字 __bridge聚假、__bridge_retained块蚌、__bridge_transfer:idobj = [[NSObjectalloc] init];void*p = (__bridgevoid*)obj;? ? 注意: __bridge不會(huì)引起對(duì)象的引用計(jì)數(shù)變化,因此魔策,安全性不太好匈子。相比較,__bridge_retained不僅僅實(shí)現(xiàn)了__bridge的功能而且能讓p調(diào)用retain方法使p持有對(duì)象闯袒。另外虎敦,? ? __bridge_transfer也是和release方法類(lèi)似游岳,使用__bridge_transfer進(jìn)行轉(zhuǎn)化,既讓對(duì)象p調(diào)用一次retain方法其徙,

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末胚迫,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子唾那,更是在濱河造成了極大的恐慌访锻,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,113評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件闹获,死亡現(xiàn)場(chǎng)離奇詭異期犬,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)避诽,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門(mén)龟虎,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人沙庐,你說(shuō)我怎么就攤上這事鲤妥。” “怎么了拱雏?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,340評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵棉安,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我铸抑,道長(zhǎng)贡耽,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,449評(píng)論 1 279
  • 正文 為了忘掉前任羡滑,我火速辦了婚禮菇爪,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘柒昏。我一直安慰自己,他們只是感情好熙揍,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,445評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布职祷。 她就那樣靜靜地躺著,像睡著了一般届囚。 火紅的嫁衣襯著肌膚如雪有梆。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,166評(píng)論 1 284
  • 那天意系,我揣著相機(jī)與錄音泥耀,去河邊找鬼。 笑死蛔添,一個(gè)胖子當(dāng)著我的面吹牛痰催,可吹牛的內(nèi)容都是我干的兜辞。 我是一名探鬼主播,決...
    沈念sama閱讀 38,442評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼夸溶,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼逸吵!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起缝裁,我...
    開(kāi)封第一講書(shū)人閱讀 37,105評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤扫皱,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后捷绑,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體韩脑,經(jīng)...
    沈念sama閱讀 43,601評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,066評(píng)論 2 325
  • 正文 我和宋清朗相戀三年粹污,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了扰才。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,161評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡厕怜,死狀恐怖衩匣,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情粥航,我是刑警寧澤琅捏,帶...
    沈念sama閱讀 33,792評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站递雀,受9級(jí)特大地震影響柄延,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜缀程,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,351評(píng)論 3 307
  • 文/蒙蒙 一搜吧、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧杨凑,春花似錦滤奈、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,352評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至伺帘,卻和暖如春昭躺,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背伪嫁。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,584評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工领炫, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人张咳。 一個(gè)月前我還...
    沈念sama閱讀 45,618評(píng)論 2 355
  • 正文 我出身青樓帝洪,卻偏偏與公主長(zhǎng)得像似舵,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子碟狞,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評(píng)論 2 344

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