洋氣的 autorelease

0枷餐、簡單的說一句

autorelease 已經(jīng)在 iOS 界叱咤風(fēng)云這么多年,現(xiàn)在網(wǎng)上也有很多類似的文章,今天也來造個輪子仓手。關(guān)于 autorelease 往往會出現(xiàn)這三個問題:

  • 1攻礼、是做什么的业踢,有什么用
  • 2、autorelease 后的對象礁扮,是在什么時候被銷毀的
  • 3知举、__autoreleasing 的使用

當(dāng)然,很多的時候提問者是直接問第2個問題,只要第2問回答正確了深员,都沒有問題了负蠕。如果是你,你會怎么回答倦畅。關(guān)于這個問題遮糖,我會先給出常規(guī)的錯誤答案,然后逐一解釋叠赐。

建議:本文主要是看過程欲账、不要追求最終的答案。想看最后答案芭概,直接看第三部分赛不。

一、錯誤回答

你是否會這樣的回答罢洲?踢故!當(dāng)運行跳出大括號之后文黎,會給當(dāng)前自動釋放池中發(fā)送過 autorelease 消息的對象都發(fā)送一條 release 消息。貌似很多的小伙伴都會這么回答殿较,遺憾的是 這個回答是錯誤的耸峭,接下來會給出錯誤的理由。十分的題淋纲、也就對了1分劳闹,在職場上回答不到8分的回答都是0分。

為什么是錯誤的回答呢洽瞬?因為與 大括號 沒有 多大 的關(guān)系本涕。具體解釋,請看下文伙窃。

在開始解釋之前菩颖,先定義一個Class,命名為:HGObject为障,定義如下:

#import <Foundation/Foundation.h>

@interface HGObject : NSObject

/** 名稱 */
@property (nonatomic, copy) NSString* name;

@end
====調(diào)皮的分割線====
#import "HGObject.h"

@implementation HGObject

- (void)dealloc {
    NSLog(@" %@ 被釋放", _name);
    [super dealloc];
}

@end

總的來說位他,就是定義了一個屬性 name,然后重寫了一下 -dealloc 方法产场。從上面的帶來來看鹅髓,我們接下來的演示中是在 MRC 環(huán)境下進行的。

二京景、與大括號的關(guān)系

2.1 不會被釋放的情況

不會被釋放

你看了之后窿冯,你會說:這肯定不會被釋放的,因為沒有再釋放池中确徙。 對醒串、很有道理,確實也是這樣鄙皇,autorelease 必須要在池子中才會有效芜赌。那么我就再遷移到池子中,看一下效果伴逸。

不會被釋放

結(jié)果還是一樣的:不會被釋放缠沈。看到這里的你是不是很激動,不信你就試試错蝴,如果釋放了記得告訴我洲愤。關(guān)于這種情況,也有這么解釋的:因為這里的 autoreleasepool 沒有被釋放顷锰,所以不會被釋放柬赐,這種解釋 100% 是錯誤的解釋。但是如果上面的兩個地方將 autorelease 換成 release 官紫,那么都是可以釋放的肛宋。

兩個地方都是可以釋放的

到這里州藕,是不是就說明了與大括號無關(guān)了?酝陈!
來簡單的分析一下慎框,在上面的兩種使用 autorelease 之后不會被釋放的情況。在上面的兩個地方后添,是一個非常不應(yīng)該的特例,因為我們一般不會在這個地方寫代碼薪丁。但是有一點很情況的是:在上面的兩個地方都沒有被進入 UIApplicationMain遇西,在 UIApplicationMain 有一個特別重要的機制,叫:運行循環(huán)严嗜,美其名曰 NSRunLoop粱檀。如果說能想到這一點,那么就算是入門了漫玄。

看到上面的介紹茄蚯,你會不會又會很激動的說:對啊,我說的就是在運行循環(huán)中的與大括號有關(guān)的睦优,在大括號結(jié)束之后就釋放了渗常。 還想說的是,這也是錯誤的汗盘。是與大括號有關(guān)系皱碘,但是并不是 一層的關(guān)系。

2.2 與大括號的那一層關(guān)系

先看一下這個代碼:


image.png

關(guān)于上面的代碼隐孽,當(dāng)我點擊屏幕的時候癌椿,會打印
兩個 log 日志信息, 是先打印 testAutorelease 執(zhí)行完畢 呢菱阵,還是先打印 obj 對象 被釋放踢俄。思考一下、把你的答案放在心中晴及,稍后公布答案都办。

虑稼。
脆丁,

动雹;


0
9
8
7
6
5
4
3
2
1


正確的順序

看到這個結(jié)果槽卫,不知道是否有小伙伴開始懷疑人生。關(guān)于這個問題胰蝠,我們先來打兩個斷點:


兩個特別的斷點

其實我們通過上面的結(jié)論歼培,當(dāng)斷點跳過 32 行的斷點之后震蒋,obj 是沒有被銷毀的,那么運行到 26 行的時候是否被銷毀了呢躲庄?我們試一下:

26 行沒有被銷毀

對查剖、運行到 26 行依然沒有被銷毀,那么問題來了:到底是在什么時候銷毀的呢噪窘?你可能會說:這不廢話么笋庄?那肯定是 26 行之后就銷毀了。現(xiàn)象是沒有錯的倔监,的確是在 26 行之后就銷毀了直砂。但是在揭穿真面目之前,還想再做一個實驗浩习,將代碼換成這樣的:

image.png

通過上面的介紹静暂,這里的打印 log 的順序是什么呢?這個得要很認(rèn)真的思考了谱秽。

洽蛀、


疟赊,
郊供、



0
9
8
7
6
5
4
3
2
1

你的答案對么近哟?

其實轉(zhuǎn)了一圈颂碘,恐怕都暈了吧锅劝。至此 autorelease 與大括號的關(guān)系讹剔,大家都有一個明確的理解了。以后別人問你的話劲赠,你還會怎么回答呢鼠证?

三峡竣、最后一公里

在揭穿之前,希望大家靜一靜量九,我們先來介紹一個小指令适掰,關(guān)于 lldb 的。很多時候我們總想看一個事件的調(diào)用棧荠列,我們可以使用這樣的代碼:

// 單元調(diào)用棧
NSLog(@"%@", [NSThread callStackSymbols]);

也可以直接在 lldb 中這樣使用:

po [NSThread callStackSymbols]

以上都是可以的类浪,但是還有一個更簡單的, 直接在 lldb 處輸入 bt肌似, 然后回車即可费就。

我為什么要介紹這個呢?是因為很多的時候 Xcode 的這里是顯示不全的:


現(xiàn)在的 Xocde 很多有用的都被省略了

現(xiàn)在的 Xocde 很多有用的都被省略了川队,想看只能通過命令了力细。賺了一圈睬澡,也大了不少的斷點,就是沒有在 HGObject 中的 -dealloc 中打過斷點眠蚂,要想知道 autorelease 的對象是在什么時候被釋放的煞聪,直接在這個地方打個斷點看看不就可以了么?是啊逝慧、我的錯昔脯,把這里給忘記了。[勇于承認(rèn)錯誤笛臣,是我一直以來的光榮傳統(tǒng)美德]云稚。

那么我們就上面的那個狀態(tài),執(zhí)行以下 bt 指令捐祠,信息如下:

重在此圖

這張圖片的信息,粗略的介紹一下桑李。通過這張圖片能看到一個陌生既熟悉的關(guān)鍵字 AutoreleasePoolPage踱蛀,這又是什么?借用在一個微信群中某大神的一個解釋贵白,他的原話:autoreleasepool不是一個大棧率拒,是分一個一個固定大小的page,雙向鏈表連起來的禁荒。這里面所指的 page 應(yīng)該就是這個 AutoreleasePoolPage猬膨。具體這個 pop 是在什么時候被調(diào)用的,這與 NSRunloop 有關(guān)呛伴。

四勃痴、關(guān)于 __autoreleasing

可以先看一下這段代碼,想一下具體的打印順序是什么热康?

__weak id obj = nil;
{
    {
        {
            {
                //  打開下面的注釋, 分別看效果
                /** __autoreleasing */ HGPerson* person = [[HGPerson alloc] init];
                NSLog(@"%@", person);
                obj = person;
                
                NSLog(@"errr");
            }
            NSLog(@"end-1");
        }
        NSLog(@"end-2");
    }
    NSLog(@"end-3");
}
NSLog(@"end-4");

// 打印 obj 的值
NSLog(@"obj = %@", obj);

__autoreleasing 這個修飾符沛申,是相對于 ARC 才有效的。所以上面的代碼需要在 ARC 環(huán)境運行才能看到效果姐军。所以說:MRC 中有 autorelease 方法铁材, ARC 中有__autoreleasing 修飾符

五奕锌、推薦

推薦一下我的其它文章:

  • 1著觉、定時器集合:介紹了所有定時器的用法以及注意事項。
  • 2惊暴、簡單易用 的 iOS 分類 : 主要是文本編輯與正則表達式的封裝饼丘。
  • 3、神氣的 iOS 打包 :不知道為什么這篇文章的點擊率很高辽话,剛剛還有小伙伴在點贊葬毫≌蚧裕可能是因為標(biāo)題取得有點霸氣。
  • 4贴捡、iOS單例的精心設(shè)計歷程 : 開發(fā)中應(yīng)該不會這么去設(shè)計一個單例忽肛,但是這里面介紹了很多的細節(jié),值得學(xué)習(xí)參考烂斋。

謝謝屹逛!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市汛骂,隨后出現(xiàn)的幾起案子罕模,更是在濱河造成了極大的恐慌,老刑警劉巖帘瞭,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件淑掌,死亡現(xiàn)場離奇詭異,居然都是意外死亡蝶念,警方通過查閱死者的電腦和手機抛腕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來媒殉,“玉大人担敌,你說我怎么就攤上這事⊥⑷兀” “怎么了全封?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長桃犬。 經(jīng)常有香客問我刹悴,道長,這世上最難降的妖魔是什么攒暇? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任颂跨,我火速辦了婚禮,結(jié)果婚禮上扯饶,老公的妹妹穿的比我還像新娘恒削。我一直安慰自己,他們只是感情好尾序,可當(dāng)我...
    茶點故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布钓丰。 她就那樣靜靜地躺著,像睡著了一般每币。 火紅的嫁衣襯著肌膚如雪携丁。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天,我揣著相機與錄音梦鉴,去河邊找鬼李茫。 笑死,一個胖子當(dāng)著我的面吹牛肥橙,可吹牛的內(nèi)容都是我干的魄宏。 我是一名探鬼主播,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼存筏,長吁一口氣:“原來是場噩夢啊……” “哼宠互!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起椭坚,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤予跌,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后善茎,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體券册,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年垂涯,在試婚紗的時候發(fā)現(xiàn)自己被綠了烁焙。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡集币,死狀恐怖考阱,靈堂內(nèi)的尸體忽然破棺而出翠忠,到底是詐尸還是另有隱情鞠苟,我是刑警寧澤,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布秽之,位于F島的核電站当娱,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏考榨。R本人自食惡果不足惜跨细,卻給世界環(huán)境...
    茶點故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望河质。 院中可真熱鬧冀惭,春花似錦、人聲如沸掀鹅。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽乐尊。三九已至戚丸,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間扔嵌,已是汗流浹背限府。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工夺颤, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人胁勺。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓世澜,卻偏偏與公主長得像,于是被迫代替她去往敵國和親姻几。 傳聞我的和親對象是個殘疾皇子宜狐,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,762評論 2 345

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