洋气的 autorelease

0、简单的说一句

autorelease 已经在 iOS 界叱咤风云这么多年,现在网上也有很多类似的文章,今天也来造个轮子。关于 autorelease 往往会出现这三个问题:

  • 1、是做什么的,有什么用
  • 2、autorelease 后的对象,是在什么时候被销毁的
  • 3、__autoreleasing 的使用

当然,很多的时候提问者是直接问第2个问题,只要第2问回答正确了,都没有问题了。如果是你,你会怎么回答。关于这个问题,我会先给出常规的错误答案,然后逐一解释。

建议:本文主要是看过程、不要追求最终的答案。想看最后答案,直接看第三部分。

一、错误回答

你是否会这样的回答?!当运行跳出大括号之后,会给当前自动释放池中发送过 autorelease 消息的对象都发送一条 release 消息。貌似很多的小伙伴都会这么回答,遗憾的是 这个回答是错误的,接下来会给出错误的理由。十分的题、也就对了1分,在职场上回答不到8分的回答都是0分。

为什么是错误的回答呢?因为与 大括号 没有 多大 的关系。具体解释,请看下文。

在开始解释之前,先定义一个Class,命名为:HGObject,定义如下:

#import <Foundation/Foundation.h>

@interface HGObject : NSObject

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

@end
====调皮的分割线====
#import "HGObject.h"

@implementation HGObject

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

@end

总的来说,就是定义了一个属性 name,然后重写了一下 -dealloc 方法。从上面的带来来看,我们接下来的演示中是在 MRC 环境下进行的。

二、与大括号的关系

2.1 不会被释放的情况

不会被释放

你看了之后,你会说:这肯定不会被释放的,因为没有再释放池中。 对、很有道理,确实也是这样,autorelease 必须要在池子中才会有效。那么我就再迁移到池子中,看一下效果。

不会被释放

结果还是一样的:不会被释放。看到这里的你是不是很激动,不信你就试试,如果释放了记得告诉我。关于这种情况,也有这么解释的:因为这里的 autoreleasepool 没有被释放,所以不会被释放,这种解释 100% 是错误的解释。但是如果上面的两个地方将 autorelease 换成 release ,那么都是可以释放的。

两个地方都是可以释放的

到这里,是不是就说明了与大括号无关了?!
来简单的分析一下,在上面的两种使用 autorelease 之后不会被释放的情况。在上面的两个地方,是一个非常不应该的特例,因为我们一般不会在这个地方写代码。但是有一点很情况的是:在上面的两个地方都没有被进入 UIApplicationMain,在 UIApplicationMain 有一个特别重要的机制,叫:运行循环,美其名曰 NSRunLoop。如果说能想到这一点,那么就算是入门了。

看到上面的介绍,你会不会又会很激动的说:对啊,我说的就是在运行循环中的与大括号有关的,在大括号结束之后就释放了。 还想说的是,这也是错误的。是与大括号有关系,但是并不是 一层的关系。

2.2 与大括号的那一层关系

先看一下这个代码:


image.png

关于上面的代码,当我点击屏幕的时候,会打印
两个 log 日志信息, 是先打印 testAutorelease 执行完毕 呢,还是先打印 obj 对象 被释放。思考一下、把你的答案放在心中,稍后公布答案。







0
9
8
7
6
5
4
3
2
1


正确的顺序

看到这个结果,不知道是否有小伙伴开始怀疑人生。关于这个问题,我们先来打两个断点:


两个特别的断点

其实我们通过上面的结论,当断点跳过 32 行的断点之后,obj 是没有被销毁的,那么运行到 26 行的时候是否被销毁了呢?我们试一下:

26 行没有被销毁

对、运行到 26 行依然没有被销毁,那么问题来了:到底是在什么时候销毁的呢?你可能会说:这不废话么?那肯定是 26 行之后就销毁了。现象是没有错的,的确是在 26 行之后就销毁了。但是在揭穿真面目之前,还想再做一个实验,将代码换成这样的:

image.png

通过上面的介绍,这里的打印 log 的顺序是什么呢?这个得要很认真的思考了。







0
9
8
7
6
5
4
3
2
1

你的答案对么?

其实转了一圈,恐怕都晕了吧。至此 autorelease 与大括号的关系,大家都有一个明确的理解了。以后别人问你的话,你还会怎么回答呢?

三、最后一公里

在揭穿之前,希望大家静一静,我们先来介绍一个小指令,关于 lldb 的。很多时候我们总想看一个事件的调用栈,我们可以使用这样的代码:

// 单元调用栈
NSLog(@"%@", [NSThread callStackSymbols]);

也可以直接在 lldb 中这样使用:

po [NSThread callStackSymbols]

以上都是可以的,但是还有一个更简单的, 直接在 lldb 处输入 bt, 然后回车即可。

我为什么要介绍这个呢?是因为很多的时候 Xcode 的这里是显示不全的:


现在的 Xocde 很多有用的都被省略了

现在的 Xocde 很多有用的都被省略了,想看只能通过命令了。赚了一圈,也大了不少的断点,就是没有在 HGObject 中的 -dealloc 中打过断点,要想知道 autorelease 的对象是在什么时候被释放的,直接在这个地方打个断点看看不就可以了么?是啊、我的错,把这里给忘记了。[勇于承认错误,是我一直以来的光荣传统美德]。

那么我们就上面的那个状态,执行以下 bt 指令,信息如下:

重在此图

这张图片的信息,粗略的介绍一下。通过这张图片能看到一个陌生既熟悉的关键字 AutoreleasePoolPage,这又是什么?借用在一个微信群中某大神的一个解释,他的原话:autoreleasepool不是一个大栈,是分一个一个固定大小的page,双向链表连起来的。这里面所指的 page 应该就是这个 AutoreleasePoolPage。具体这个 pop 是在什么时候被调用的,这与 NSRunloop 有关。

四、关于 __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 环境运行才能看到效果。所以说:MRC 中有 autorelease 方法, ARC 中有__autoreleasing 修饰符

五、推荐

推荐一下我的其它文章:

  • 1、定时器集合:介绍了所有定时器的用法以及注意事项。
  • 2、简单易用 的 iOS 分类 : 主要是文本编辑与正则表达式的封装。
  • 3、神气的 iOS 打包 :不知道为什么这篇文章的点击率很高,刚刚还有小伙伴在点赞。可能是因为标题取得有点霸气。
  • 4、iOS单例的精心设计历程 : 开发中应该不会这么去设计一个单例,但是这里面介绍了很多的细节,值得学习参考。

谢谢!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,602评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,442评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,878评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,306评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,330评论 5 373
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,071评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,382评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,006评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,512评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,965评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,094评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,732评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,283评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,286评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,512评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,536评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,828评论 2 345

推荐阅读更多精彩内容