前言
從我開(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方法其徙,