现代iOS 8 NSOperation使用仍然需要@autoreleasepool吗?

时间:2014-07-03 19:38:35

标签: ios automatic-ref-counting nsoperation ios8 nsautoreleasepool

我已阅读Concurrency Programming Guide

在指南中,文本声明GCD调度队列定义了他们自己的@autoreleasepool池,并提到仍然建议在每个调度级别定义一个,但是对于NSOperation没有说什么,Apple提供的示例代码也没有显示@autoreleasepool结构的用法。在NSOperation的背景下,模糊地提到@autoreleasepool的唯一地方是修订历史,

  

2012-07-17 - 删除了有关使用操作的自动释放池使用情况的过时信息。

查看在线提供的示例代码,例如http://www.raywenderlich.com/19788/how-to-use-nsoperations-and-nsoperationqueues在基于NSOperations的对象的实现中使用@autoreleasepool,例如:

@implementation ImageDownloader

- (void)main {
    @autoreleasepool {
      ...
    }
}     
@end
  1. 我应该如何实现现代NSOperation对象?
  2. Apple在2012-07-17之间提到的更新是什么?

1 个答案:

答案 0 :(得分:35)

如果您派生自NSOperation并实施main方法,则无需设置自动释放池。 start方法的默认实现会推送NSAutoReleasePool,调用main,然后弹出NSAutoReleasePoolNSInvocationOperationNSBlockOperation也是如此,它们共享start方法的相同实现。

以下是对start的{​​{1}}方法的简略反汇编。注意调用NSPushAutoreleasePool,然后调用main,然后调用NSPopAutoreleasePool:

NSOperation

以下是运行

的一些示例代码的快照
  1. Foundation`-[newMyObj__NSOperationInternal _start:]: 0x7fff8e5df30f: pushq %rbp ... 0x7fff8e5df49c: callq *-0x16b95bb2(%rip) ; (void *)0x00007fff8d9d30c0: objc_msgSend 0x7fff8e5df4a2: movl $0x1, %edi ; new NSAutoreleasePool is pushed here 0x7fff8e5df4a7: callq 0x7fff8e5df6d6 ; NSPushAutoreleasePool ... NSOperation main is called 0x7fff8e5df6a4: callq *-0x16b95dba(%rip) ; (void *)0x00007fff8d9d30c0: objc_msgSend 0x7fff8e5df6aa: movq %r15, %rdi ; new NSAutoreleasePool is popped here, which releases any objects added in the main method 0x7fff8e5df6ad: callq 0x7fff8e5e1408 ; NSPopAutoreleasePool MyObj方法中分配,我确保该对象必须自动释放
  2. main返回main,下图显示当前自动释放池调用_start的堆栈跟踪,弹出MyObj dealloc
  3. call stack showing object is released when NSPopAutoreleasePool is called

    作为参考,这是我用来验证行为的示例代码:

    _start

    Grand Central Dispatch同样根据Concurrency Programming Guide管理调度队列的自动释放池:

      

    如果您的块创建了多个Objective-C对象,您可能希望将块的代码部分包含在@autorelease块中,以处理这些对象的内存管理。尽管GCD调度队列具有自己的自动释放池,但它们无法保证这些池何时耗尽。如果您的应用程序受内存限制,则创建自己的自动释放池可以让您以更加固定的时间间隔释放自动释放对象的内存。