? ? ? 在運(yùn)行程序的過程中,需要創(chuàng)建大量的對象磅轻。對象從創(chuàng)建出來马澈、使用之后痊班,就需要對內(nèi)存中的對象進(jìn)行釋放,不然內(nèi)存中的垃圾對象會越來越多馒胆,造成內(nèi)存泄漏,從而嚴(yán)重影響程序的運(yùn)行效率睦尽,甚至?xí)鹣到y(tǒng)的crash当凡。而C#纠俭、JAVA等高級語言都有較為完善的回收機(jī)制(GC)來解決無效對象的問題。但是在Ojbc中卻缺少相應(yīng)的較為完善的內(nèi)存管理機(jī)制朴则。在早先的Xcode版本中乌妒,對象的釋放需要開發(fā)者純手動進(jìn)行釋放外邓。目前Apple已經(jīng)在近些年開始引入的自動回收的機(jī)制坐榆。但是并不是全自動的,所以主要講解一下Objc的內(nèi)存管理問題匹中。
首先豪诲,需要說明的是屎篱,Xcode4.2之后引入了ARC機(jī)制,是Xcode項(xiàng)目在啟動時默認(rèn)的選項(xiàng)重虑。需要自己手動關(guān)閉ARC功能缺厉。在Xcode中關(guān)閉ARC:項(xiàng)目屬性—Build Settings--搜索“garbage”找到Objective-C Automatic Reference Counting設(shè)置為No即可。
引用計數(shù)器
首先命爬,在JAVA等高級語言中辐脖,GC會自動管理內(nèi)存嗜价。當(dāng)實(shí)例化一個對象之后會有一個變量來引用該對象(引用的實(shí)質(zhì)是變量會存儲對象的物理地址),當(dāng)該變量不再引用的時候练链,GC就會自動回收之前的對象奴拦。也就是說错妖,創(chuàng)建的對象一旦沒有任何變量引用他疚沐,那么就將被回收亮蛔。
但是,Ojbc中沒有類似的垃圾回收機(jī)制辣吃。而OC引入了對象引用計數(shù)器來管理內(nèi)存。在OC中芬探,每一個對象在生成之時都會有一個與他對應(yīng)的整數(shù)(retainCount)神得,叫做“引用計數(shù)器”,用來實(shí)時記錄改對象被引用與釋放的次數(shù)偷仿,當(dāng)對象創(chuàng)建之初哩簿,就會被默認(rèn)為reainCount為1。內(nèi)存在判斷一個對象何時釋放的唯一依據(jù)就是判斷該對象的引用計數(shù)是否為0酝静。在OC中节榜,調(diào)用對象的alloc、retain别智、new宗苍、copy時亿遂,計數(shù)器都會自動的在原基礎(chǔ)上+1浓若,當(dāng)調(diào)用release時計數(shù)器-1渺杉。當(dāng)release到對象的retainCount為0時,系統(tǒng)對調(diào)用該對象的dealloc方法將其銷毀挪钓。
舉例:
我創(chuàng)建一個ARCObject類是越,并且復(fù)寫它的dealloc對象方法
//? ARCObject.m
//? ARCTest
//
//? Created by workMAC on 16/8/12.
//? Copyright ? 2016年 yichen Wang. All rights reserved.
//
#import "ARCObject.h"
@implementation ARCObject
@synthesize number;
-(void)dealloc
{
NSLog(@"銷毀對象");
[super dealloc];
}
@end
在主函數(shù)做如下代碼調(diào)用:
ARCObject * ARCStr = [[ARCObject alloc] init];
[ARCStr retain];
NSLog(@"retainCount=%lu",[ARCStr retainCount]);
[ARCStr release];
NSLog(@"retainCount=%lu",[ARCStr retainCount]);
此時打印的retainCount為
2016-08-15 16:15:37.092 ARCTest[3717:184315] retainCount=2
2016-08-15 16:15:37.092 ARCTest[3717:184315] retainCount=1
可以看到在retain方法被調(diào)用后的retainCount加1,release減1碌上。而此時再次release倚评,則引用計數(shù)將變?yōu)?,代碼將執(zhí)行ARCObject的dealloc方法馏予。這時可以看到控制臺打犹煳唷:
2016-08-15 16:22:10.215 ARCTest[3773:188463] 銷毀對象
注意:
在最終release銷毀對象成功以后,需要我們手動為ARCStr設(shè)置其變量為nil霞丧。否則會出現(xiàn)野指針的情況(即該對象已經(jīng)不屬于本程序呢岗,在對他進(jìn)行調(diào)用等操作是很危險的)還有一點(diǎn)就是,Objc中給空對象發(fā)送消息是不會引起什么錯誤的蛹尝,所以應(yīng)該注意釋放的嚴(yán)謹(jǐn)性和完整性后豫。完整的釋放一個對象應(yīng)該如此:
ARCObject * ARCStr = [[ARCObject alloc] init];
[ARCStr retain];
NSLog(@"retainCount=%lu",[ARCStr retainCount]);
[ARCStr release];
NSLog(@"retainCount=%lu",[ARCStr retainCount]);
[ARCStr release];
ARCStr = nil;
[ARCStr release];
內(nèi)存釋放的原則
在項(xiàng)目中,手動管理面臨許多問題突那,尤其在對象之間來回引用的時候會造成很多不準(zhǔn)確挫酿,即retain和release的計數(shù)最終并不能對應(yīng)上。因此就需要遵循一個原則:誰創(chuàng)建愕难,誰釋放早龟。誰引用,誰釋放猫缭。
屬性參數(shù)
這里要講到的是我們在定義類所使用的對像時葱弟,@property括號中的內(nèi)容問題。
在進(jìn)行計數(shù)的時候饵骨,都是我們在方法里對對象進(jìn)行retain翘悉、release的操作來控制它的引用計數(shù)器。那么通過@property其實(shí)是可以實(shí)現(xiàn)不調(diào)用對象的setter居触、getter方法來自動實(shí)現(xiàn)的妖混。自動處理而不會造成內(nèi)存泄漏。括號內(nèi)的參數(shù)的意義如下:
從上邊也可以看到轮洋,@property的參數(shù)分為三類制市,也就是說它可以被三個不同種類的詞修飾。三個詞如果不設(shè)置弊予,或者只設(shè)置一個祥楣,那么程序會默認(rèn)三個的默認(rèn)參數(shù):(atomic,readwrite,assign),一個最安全,最基本的參數(shù)類型误褪。
首先原子性來說责鳍,一般除非開啟線程使用atomic,否則請考慮使用nonatomic來修飾兽间,它的性能更好历葛,速度更快。
讀寫屬性嘀略,通俗講:readwrite可以對改對象之行讀寫操作恤溶,而readonly只能讀取不可寫入更改。
set的方法處理里帜羊,assign是直接賦值的咒程。一般來說,在int等類型修飾較多讼育。retain多用于非字符串的對象帐姻。copy多用來修飾字符串對象、block窥淆、NSArray卖宠、NSDictionary。
自動釋放池
Xcode4.2以后引入的ARC機(jī)制叫做“自動引用計數(shù)”(或“自動釋放池”)忧饭,它相比前邊提到的JAVA等語言的內(nèi)存管理差很多,其實(shí)也可以說是半自動的一種內(nèi)存管理筷畦。它通過對@autoreleasepool聲明一個函數(shù)塊词裤。
//? main.m
//? guigutang
//
//? Created by 王一臣 on 16/6/16.
//? Copyright ? 2016年 tuzhi Information Technology. All rights reserved.//#import#import "AppDelegate.h"
int main(int argc, char * argv[])
{
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
那么生成一個對象,在初試進(jìn)入這個方法時調(diào)用了autorelease鳖宾,那么代碼執(zhí)行完畢之后吼砂,在@autoreleasepool塊中,調(diào)用過autorelease的對象都將自動調(diào)用一次release鼎文。看到這里應(yīng)該能明白了渔肩,OC中的自動管理,指的就是提對象自動釋放一次拇惋。所以它并不能保證對象一定會被回收周偎,因?yàn)樗皇钦{(diào)用一個release,并不是保證reatinCount為0撑帖。
注意:
1.自動緩存機(jī)制中蓉坎,對象調(diào)用autorelease并不會引起retainCount的改變,只是把改對象放在了自動釋放池中胡嘿。在@autoreleasepool塊執(zhí)行完畢蛉艾,最后對釋放池的對象統(tǒng)一release一次。
2.自動釋放池的ARC機(jī)制,實(shí)質(zhì)是在程序最后統(tǒng)一調(diào)用對象的release方法一次勿侯,并不表示一定會銷毀對象(前頭有說過拓瞪,銷毀對象的唯一依據(jù)是retainCount為0)
3.Objc中的類庫的靜態(tài)方法一般自帶autorelease方法,不需要手動釋放助琐。
4.由于自動釋放池都是在程序最后統(tǒng)一銷毀對象吴藻,所以如果一個操作很占內(nèi)存,弓柱,或者其對象在過程中非常占用內(nèi)存沟堡,那么請考慮把對象不要放自動釋放池,或者說放在多個矢空。最好是不好以來Xcode的ARC機(jī)制航罗。比如SDWebImage在UITableview的框架下加載大量的高質(zhì)量gif時,其實(shí)會有很大的內(nèi)存漏洞屁药,會直接導(dǎo)致APP內(nèi)存爆炸粥血,程序會出現(xiàn)crash。所以酿箭,內(nèi)存管理還是需要非常重視的复亏!