洋氣的 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)運(yùn)行跳出大括號之后,會給當(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)境下進(jìn)行的。

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

2.1 不會被釋放的情況

不會被釋放

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

不會被釋放

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

兩個地方都是可以釋放的

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

看到上面的介紹,你會不會又會很激動的說:對啊,我說的就是在運(yùn)行循環(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 是沒有被銷毀的,那么運(yùn)行到 26 行的時候是否被銷毀了呢?我們試一下:

26 行沒有被銷毀

對、運(yùn)行到 26 行依然沒有被銷毀,那么問題來了:到底是在什么時候銷毀的呢?你可能會說:這不廢話么?那肯定是 26 行之后就銷毀了?,F(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)境運(yùn)行才能看到效果。所以說:MRC 中有 autorelease 方法, ARC 中有__autoreleasing 修飾符。

五、推薦

推薦一下我的其它文章:

  • 1、定時器集合:介紹了所有定時器的用法以及注意事項。
  • 2、簡單易用 的 iOS 分類 : 主要是文本編輯與正則表達(dá)式的封裝。
  • 3、神氣的 iOS 打包 :不知道為什么這篇文章的點擊率很高,剛剛還有小伙伴在點贊??赡苁且驗闃?biāo)題取得有點霸氣。
  • 4、iOS單例的精心設(shè)計歷程 : 開發(fā)中應(yīng)該不會這么去設(shè)計一個單例,但是這里面介紹了很多的細(xì)節(jié),值得學(xué)習(xí)參考。

謝謝!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容