如果你从NSOperation
派生并实现了main
方法,则不需要设置自动释放池。 start
方法的默认实现会推入一个NSAutoReleasePool
,调用main
,然后随即弹出NSAutoReleasePool
。同样适用于NSInvocationOperation
和NSBlockOperation
,它们共享start
方法的同一实现。
下面是NSOperation
的start
方法的简略反汇编代码。请注意对NSPushAutoreleasePool的调用,然后是对main的调用,最后是对NSPopAutoreleasePool的调用:
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
在 main
方法中被分配,并确保该对象必须被自动释放。
main
返回到 _start
,下面的图片显示了一个堆栈跟踪,其中 MyObj dealloc
由当前的自动释放池调用,在 _start
中弹出。
![call stack showing object is released when NSPopAutoreleasePool is called](https://istack.dev59.com/xM3Xp.webp)
供参考,这是我用来验证此行为的示例代码:
#import <Foundation/Foundation.h>
@interface MyObj : NSObject
@end
@implementation MyObj
- (void)dealloc {
NSLog(@"dealloc");
}
@end
@interface TestOp : NSOperation {
MyObj *obj;
}
@end
@implementation TestOp
- (MyObj *)setMyObj:(MyObj *)o {
MyObj *old = obj;
obj = o;
return old;
}
- (void)main {
MyObj *old = [self setMyObj:[MyObj new]];
[self setMyObj:old];
}
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSLog(@"Hello, World!");
NSOperationQueue *q = [NSOperationQueue new];
TestOp *op = [TestOp new];
[q addOperation:op];
[op waitUntilFinished];
}
return 0;
}
根据并发编程指南,Grand Central Dispatch同样管理调度队列的自动释放池:
如果您的块创建了超过少量的Objective-C对象,则可能需要将块代码的某些部分封装在@autorelease块中,以便处理这些对象的内存管理。虽然GCD调度队列有它们自己的自动释放池,但它们不能保证何时将这些池排空。如果您的应用程序受内存约束,那么创建自己的自动释放池可以让您更定期地释放自动释放对象的内存。