美文网首页将来跳槽用麦子面试题精选转载iOS
iOS面试题:一个 autorealese 对象在什么时刻释放?

iOS面试题:一个 autorealese 对象在什么时刻释放?

作者: iOS猿_员 | 来源:发表于2019-01-29 20:54 被阅读459次

    原文:iOS面试题大全

    分两种情况:手动干预释放时机、系统自动去释放。

    • 手动干预释放时机:手动指定 autoreleasepool 的 autorelease 对象,在当前作用域大括号结束时释放。
    • 系统自动去释放:不手动指定 autoreleasepool 的 autorelease 对象出了作用域之后,会被添加到最近一次创建的自动释放池中,并会在当前的 runloop 迭代结束时释放。而它能够释放的原因是系统在每个 runloop 迭代中都加入了自动释放池 Push 和 Pop。一个典型的例子是在一个类方法中创建一个对象并作为返回值,这时就需要将该对象放置到对应的 autoreleasepool 中。

    例子:

        __weak id reference = nil;
        - (void)viewDidLoad {
            [super viewDidLoad];
            NSString *str = [NSString stringWithFormat:@"aaa"];
            // str 是一个 autorelease 对象,设置一个 weak 的引用来观察它。
            reference = str;
        }
        - (void)viewWillAppear:(BOOL)animated {
            [super viewWillAppear:animated];
            NSLog(@"%@", reference); // Console: aaa
        }
        - (void)viewDidAppear:(BOOL)animated {
            [super viewDidAppear:animated];
            NSLog(@"%@", reference); // Console: (null)
        }
    

    由于这个 vc 在 loadView 之后便 add 到了 window 层级上,所以 viewDidLoad 和 viewWillAppear 是在同一个 runloop 调用的,因此在 viewWillAppear 中,这个 autorelease 的变量依然有值。而在 viewDidAppear 执行之前这个 autorelease 的变量已经被释放了。

    从程序启动到加载完成是一个完整的 runloop,然后会停下来,等待用户交互,用户的每一次交互都会启动一次 runloop,来处理用户所有的点击事件、触摸事件。

    我们都知道:所有 autorelease 的对象,在出了作用域之后,会被自动添加到最近创建的自动释放池中。

    但是如果每次都放进应用程序的 main.m 中的 autoreleasepool 中,迟早有被撑满的一刻。所以在每一次完整的 runloop 结束之前,对于的自动释放池里面的 autorelease 对象会被销毁。那这个自动释放池是什么时候创建的呢?答案是,在 runloop 检测到事件并启动后,就会创建对应的自动释放池。

    子线程的 runloop 默认是不工作,无法主动创建,必须手动创建。

    自定义的 NSOperation 和 NSThread 需要手动创建自动释放池。比如:自定义的 NSOperation 类中的 main 方法里就必须添加自动释放池。否则出了作用域后,自动释放对象会因为没有自动释放池去处理它,而造成内存泄露。但对于 blockOperation 和 invocationOperation 这种默认的 Operation ,系统已经帮我们封装好了,不需要手动创建自动释放池。

    @autoreleasepool 当自动释放池被销毁或者耗尽时,会向自动释放池中的所有对象发送 release 消息,释放自动释放池中的所有对象。

    相关文章

      网友评论

        本文标题:iOS面试题:一个 autorealese 对象在什么时刻释放?

        本文链接:https://www.haomeiwen.com/subject/mtdfsqtx.html