iOS循序漸進(jìn)之篇四:OC對象的生成和釋放

篇三上說iOS ARC(Automatic Reference Counting)管理的是堆上的OC對象。

1 開發(fā)人員對OC對象管理的四條規(guī)則

  • 自己生成的對象搞动,自己持有
  • 非自己生成的對象,自己也能持有
  • 不需要自己持有的對象時(shí)釋放
  • 非自己持有的對象不能釋放
    上面的四條規(guī)則能夠幫助開發(fā)人員完成對OC對象的聲明周期的管理拒课,而ARC的工作原理也是模仿這一方式僧凰,通過引用計(jì)數(shù)。它會在合適的地方給我添加對OC對象的引用和釋放的代碼词裤。當(dāng)一個(gè)OC對象被引用時(shí),那么這個(gè)OC對象的引用數(shù)加1鳖宾;當(dāng)一個(gè)OC對象失去引用時(shí)吼砂,那么這個(gè)OC對象的數(shù)減1。當(dāng)OC對象引用數(shù)為0的時(shí)候就會被系統(tǒng)回收鼎文,回收的時(shí)機(jī)在下一個(gè)RunLoop循環(huán)開始渔肩,回收上一個(gè)循環(huán)的OC對象

2 在內(nèi)存中管理對象的操作方法

Objective-c 方法名 功能
alloc/new/copy/mutableCopy 方法 生成并持有對象拇惋,即使用這些方法生成對象周偎,那么對這個(gè)對象的引用至少為1
retain 方法 持有對象抹剩,即使這個(gè)對象的引用數(shù)加1
release 方法 釋放對象,即使這個(gè)對象的引用數(shù)減1蓉坎,當(dāng)這個(gè)引用數(shù)為0的時(shí)候吧兔,系統(tǒng)自動(dòng)調(diào)用dealloc方法釋放對象所占用的空間
dealloc 方法 釋放對象,這個(gè)釋放必須是對象的引用數(shù)為零才能釋放

2.1 Tips:copy和mutableCopy的區(qū)別

方法 功能 協(xié)議 實(shí)現(xiàn) 可變對象調(diào)用 不可變對象調(diào)用
copy 生成并持有不可變對象的副本 NSCopying copyWithZone: 深復(fù)制 淺復(fù)制
mutableCopy 生成并持有可變對象的副本 NSMutableCopying mutableCopyWithZone: 深復(fù)制 深復(fù)制

由 上表可以知道袍嬉,使用copy方法復(fù)制的并不都是淺復(fù)制,為了避免出錯(cuò)灶平,如果要對一個(gè)對象進(jìn)行深復(fù)制伺通,則使用mutableCopy方法。

2.2 autorelease/__autoreleasing 關(guān)鍵字

autorelease是在MRC環(huán)境下的關(guān)鍵字逢享,而__autoreleasingARC環(huán)境下的關(guān)鍵字罐监,它們是等價(jià)的,只是看編譯環(huán)境是不是支持ARC瞒爬。該關(guān)鍵字:它可以取得對象弓柱,但是不持有對象,利用這個(gè)特性我們可以在下面的方法中返回一個(gè)不會被持有的對象和降低內(nèi)存峰值侧但。

-(id) object{
  id obj = [NSObject new];
  [obj autorelease]; // obj不持有[NSObject new] 生成的對象
  return obj; // 等價(jià)于返回一個(gè)引用
}

問題1:為什么autorelease它可以取得對象矢空,但是不持有對象?
原因是: 調(diào)用這個(gè)方法禀横,它可以把這個(gè)對象加入到自動(dòng)釋放池中屁药,在清理自動(dòng)釋放池的時(shí)候,系統(tǒng)自動(dòng)會為釋放池中的對象調(diào)用[obj release];柏锄。
問題2:如何降低內(nèi)存峰值酿箭?
在回答這個(gè)問題之前,先介紹內(nèi)存峰值和對比在MRCARC的自動(dòng)釋放池趾娃。
內(nèi)存峰值:它是指在某一段較小的時(shí)間占用的內(nèi)存高于它鄰近時(shí)間的內(nèi)存占有量缭嫡。

在MRC環(huán)境下的創(chuàng)建自動(dòng)釋放池,分為三步驟:
第一步:生成并持有釋放池NSAutoreleasePool對象;
第二步:調(diào)用對象的autorelease方法抬闷,使對象加入連接池中;
第三步:釋放NSAutoreleasePool對象妇蛀,然后系統(tǒng)會對這個(gè)池中的每一個(gè)對象調(diào)用release方法;

//MRC環(huán)境下:
//第一步:生成并持有釋放池NSAutoreleasePool對象;
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

// 在堆內(nèi)存中生成一個(gè)對象
id obj = [[NSObject alloc] init];

// 第二步:調(diào)用autorelease方法,使對象加入連接池中;
[obj autorelease];

//第三步:釋放NSAutoreleasePool對象;
[pool drain];   //向池中的所有對象調(diào)用release方法饶氏,此處由系統(tǒng)調(diào)用[obj release];

//obi已經(jīng)釋放讥耗,再次調(diào)用會崩潰
NSLog(@"%@", obj); 

由上例代碼可知,對自動(dòng)釋放池的生成和釋放的代碼是固定不變的疹启,所以在ARC環(huán)境下古程,它把自動(dòng)釋放池的創(chuàng)建和釋放交給編譯器了,直接使用@autoreleasepool塊即可喊崖。例如上例可以改成:

@autoreleasepool{// 這里生成NSAutoreleasePool對象
// 在堆內(nèi)存中生成一個(gè)對象
id obj = [[NSObject alloc] init];
} // 在這里自動(dòng)調(diào)用[pool drain];

接下來假設(shè)一個(gè)減少內(nèi)存峰值的一個(gè)應(yīng)用場景:通過一個(gè)for循環(huán)加載大量文件挣磨,并用一個(gè)字符串來接收雇逞,如下所示:

// 此處只是模擬場景,
NSArray *urls = <# An array of file URLs #>;
for (NSURL *url in urls) {
      NSError *error;
      NSString *fileContents = [NSString stringWithContentsOfURL:url
                                         encoding:NSUTF8StringEncoding error:&error];
      /*處理字符串茁裙,創(chuàng)建并自動(dòng)釋放更多對象塘砸。 */
}

上例代碼,在for循環(huán)內(nèi)會占用大量的內(nèi)存晤锥,這時(shí)就會產(chǎn)生內(nèi)存峰值掉蔬,如果我們使用自動(dòng)釋放池就可以降低內(nèi)存峰值,如下所示矾瘾。

// 此處只是模擬場景女轿,
NSArray *urls = <# An array of file URLs #>;
for (NSURL *url in urls) {
 
    @autoreleasepool {
        NSError *error;
        NSString *fileContents = [NSString stringWithContentsOfURL:url
                                         encoding:NSUTF8StringEncoding error:&error];
        /*處理字符串,創(chuàng)建并自動(dòng)釋放更多對象壕翩。 */
    }// 執(zhí)行到這里蛉迹,會釋放池內(nèi)的所有局部變量,這里會把fileContents釋放掉放妈。
}

3 自動(dòng)釋放池(NSAutoreleasePool)

自動(dòng)釋放池還有一個(gè)特性就是可以嵌套使用北救,如下面所示。

@autoreleasepool {
    // . . .
    @autoreleasepool {
        // . . .
    }
  //  . . .
}

注意:雖然自動(dòng)釋放池芜抒,能夠幫助我們清理對象珍策,但是不建議大量的使用自動(dòng)釋放池,原因有二:一是雖然自動(dòng)釋放池雖然占用較小挽绩,但是大量的話也會占有一定的內(nèi)存膛壹;二是頻繁的清理對象,會消耗CPU的性能和耗電唉堪。

3.1 RunLoop和NSAutoreleasePool的關(guān)系

每一個(gè)RunLoop都會創(chuàng)建一個(gè)Autorelease Pool對象模聋,系統(tǒng)會為同一個(gè)RunLoop 的所有Autorelease Pool對維護(hù)一個(gè)棧,每個(gè)新創(chuàng)建的Autorelease Pool對象會壓入棧頂唠亚,待RunLoop結(jié)束時(shí)链方,彈出棧頂,同時(shí)清理Autorelease Pool的所有對象灶搜。

3.2 線程和NSAutoreleasePool的關(guān)系

每一個(gè)線程都會有自己的Autorelease Pool 和一個(gè)RunLoop祟蚀,但是非主線程的RunLoop,默認(rèn)不回開啟割卖,需要手動(dòng)開啟前酿。當(dāng)線程終止的時(shí)候,系統(tǒng)會自動(dòng)清理該線程的Autorelease Pool 對象鹏溯。所以在程序開始運(yùn)行的時(shí)候罢维,主線程創(chuàng)建后,RunLoop和Autorelease Pool也會創(chuàng)建丙挽,并且RunLoop啟動(dòng)肺孵。

總結(jié)

在現(xiàn)在的iOS的開發(fā)幾乎都是處于ARC環(huán)境下匀借,ARC的工作原理也是非常簡單的,就是監(jiān)控一個(gè)對象的引用數(shù)平窘,如果這個(gè)對象的引用數(shù)為0吓肋,系統(tǒng)就會回收這個(gè)對象。這樣就幫助開發(fā)人員從MRC編程釋放出來瑰艘。本文主要介紹了對一個(gè)對象從生成到釋放和在ARC環(huán)境下是鬼,@autorelease的用法和它的背后原理。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末紫新,一起剝皮案震驚了整個(gè)濱河市屑咳,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌弊琴,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,252評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件杖爽,死亡現(xiàn)場離奇詭異敲董,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)慰安,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評論 3 399
  • 文/潘曉璐 我一進(jìn)店門腋寨,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人化焕,你說我怎么就攤上這事萄窜。” “怎么了撒桨?”我有些...
    開封第一講書人閱讀 168,814評論 0 361
  • 文/不壞的土叔 我叫張陵查刻,是天一觀的道長。 經(jīng)常有香客問我凤类,道長穗泵,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,869評論 1 299
  • 正文 為了忘掉前任谜疤,我火速辦了婚禮佃延,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘夷磕。我一直安慰自己履肃,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,888評論 6 398
  • 文/花漫 我一把揭開白布坐桩。 她就那樣靜靜地躺著尺棋,像睡著了一般。 火紅的嫁衣襯著肌膚如雪撕攒。 梳的紋絲不亂的頭發(fā)上陡鹃,一...
    開封第一講書人閱讀 52,475評論 1 312
  • 那天烘浦,我揣著相機(jī)與錄音,去河邊找鬼萍鲸。 笑死闷叉,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的脊阴。 我是一名探鬼主播握侧,決...
    沈念sama閱讀 41,010評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼嘿期!你這毒婦竟也來了品擎?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,924評論 0 277
  • 序言:老撾萬榮一對情侶失蹤备徐,失蹤者是張志新(化名)和其女友劉穎萄传,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蜜猾,經(jīng)...
    沈念sama閱讀 46,469評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡秀菱,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,552評論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了蹭睡。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片衍菱。...
    茶點(diǎn)故事閱讀 40,680評論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖肩豁,靈堂內(nèi)的尸體忽然破棺而出脊串,到底是詐尸還是另有隱情,我是刑警寧澤清钥,帶...
    沈念sama閱讀 36,362評論 5 351
  • 正文 年R本政府宣布琼锋,位于F島的核電站,受9級特大地震影響祟昭,放射性物質(zhì)發(fā)生泄漏斩例。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,037評論 3 335
  • 文/蒙蒙 一从橘、第九天 我趴在偏房一處隱蔽的房頂上張望念赶。 院中可真熱鬧,春花似錦恰力、人聲如沸叉谜。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,519評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽停局。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間董栽,已是汗流浹背码倦。 一陣腳步聲響...
    開封第一講書人閱讀 33,621評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留锭碳,地道東北人袁稽。 一個(gè)月前我還...
    沈念sama閱讀 49,099評論 3 378
  • 正文 我出身青樓,卻偏偏與公主長得像擒抛,于是被迫代替她去往敵國和親推汽。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,691評論 2 361

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