Ответ 1
Если вы извлекаете из NSOperation
и внедряете метод main
, вам не нужно настраивать пул автозапуска. По умолчанию метод start
по умолчанию запускает NSAutoReleasePool
, вызывает main
, а затем выдает NSAutoReleasePool
. То же самое относится к NSInvocationOperation
и NSBlockOperation
, которые используют одну и ту же реализацию метода start
.
Ниже приведена сокращенная разборка метода start
для NSOperation
. Обратите внимание на вызовы в NSPushAutoreleasePool, затем на главный вызов, а затем на вызов 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
Для справки, это пример кода, который я использовал для проверки поведения:
#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 {
// insert code here...
NSLog(@"Hello, World!");
NSOperationQueue *q = [NSOperationQueue new];
TestOp *op = [TestOp new];
[q addOperation:op];
[op waitUntilFinished];
}
return 0;
}
Grand Central Dispatch аналогичным образом управляет пулами автораспределения для очередей отправки, за Concurrency Руководство по программированию:
Если ваш блок создает несколько объектов Objective-C, вы можете захотеть заключить части кода ваших блоков в блок @autorelease, чтобы обрабатывать управление памятью для этих объектов. Хотя очереди диспетчеризации GCD имеют свои собственные пулы автоопределений, они не дают никаких гарантий относительно того, когда эти пулы сливаются. Если ваше приложение ограничено памятью, создание собственного пула автозапуска позволяет вам освобождать память для автореализованных объектов с более регулярными интервалами.