ARC中的Autorelease

2018-05-14  本文已影响75人  conowen

MRC

使用ARC,开发者不再需要手动的retain/release/autorelease。编译器会自动插入对应的代码,再结合Objective C的runtime,实现自动引用计数。一般来说,对象的alloc、retain操作都会让引用计数+1,release则会让引用计数-1。

注意:对于某些系统类,使用alloc方法是不一定的让引用计数+1。
因为这些类的alloc方法并非简单的申请一块内存。

        NSArray *arr = [[NSArray alloc] init];
        NSLog(@"arr retainCount =%ld",arr.retainCount);
        NSObject * obj = [[NSObject alloc] init];
        [obj retain];
        NSString *str = @"test";//字符串常量系统不会收回,也不会对其作引用计数
        NSLog(@"str retainCount =%ld",str.retainCount);
        NSLog(@"obj retainCount =%ld",obj.retainCount);

输出的结果是

2018-05-14 14:17:02.687785+0800 TestMRC[91989:4598336] arr retainCount =-1
2018-05-14 14:17:02.687928+0800 TestMRC[91989:4598336] str retainCount =-1
2018-05-14 14:17:02.688025+0800 TestMRC[91989:4598336] obj retainCount =2

为什么使用了alloc还要使用init方法呢?因为内存中有很多数据并没有清零,所以需要init方法初始化一下。

autorelease

在MRC中,对某一个对象调用autorelease方法,表示延迟发送release消息,意思指的是,当我们把一个对象标记为autorelease时:[obj autorelease];,表示现在暂时不进行release操作,等这段语句所处的 autoreleasepool 进行 drain 操作时,所有标记了 autorelease 的对象的 retainCount 会被 -1。即 release 消息的发送被延迟到 pool 释放的时候了。

关于这个autoreleasepoold的问题?当用户没有手加Autorelease PoolNSAutoreleasePool的情况下,Autorelease对象是在当前的runloop的event释放的,而它能够释放的原因是系统在每个runloop迭代中都加入了自动释放池Push和Pop

在ARC中,我们并不需要手动调用 autorelease 有关的方法,就可以正确管理好内存。因为 Cocoa Touch 的 Runloop 中,每个 runloop circle 中系统都自动加入了 Autorelease Pool 的创建和释放。一般来说,当需要创建和销毁大量的对象时,使用手动创建的 autoreleasepool 可以有效的避免内存峰值的出现。因为如果不手动创建的话,外层系统创建的 pool 会在整个 runloop circle 结束之后才进行 drain,手动创建的话,会在 block 结束之后就进行 drain 操作。
一个普遍被使用的例子如下:

for (int i = 0; i < 100000000; i++)
{
    @autoreleasepool
    {
        NSString* string = @"ab c";
        NSArray* array = [string componentsSeparatedByString:string];
    }
}

如果不使用 autoreleasepool ,需要在循环结束之后释放 100000000 个字符串,如果使用的话,则会在每次循环结束的时候都进行 release 操作。

如上面所说,系统在 runloop 中创建的 autoreleaspool 会在 runloop 一个 event 结束时进行释放操作。我们手动创建的 autoreleasepool 会在 block 执行完成之后进行 drain 操作。需要注意的是:

当 block 以异常(exception)结束时,pool 不会被 drain
Pool 的 drain 操作会把所有标记为 autorelease 的对象的引用计数减一,但是并不意味着这个对象一定会被释放掉,我们可以在 autorelease pool 中手动 retain 对象,以延长它的生命周期(在 MRC 中)。

参考文章

https://hit-alibaba.github.io/interview/iOS/ObjC-Basic/MM.html

上一篇下一篇

猜你喜欢

热点阅读