¿Todavía se necesita @autoreleasepool para el uso moderno de iOS 8 NSOperation?

He leído la Guía de progtwigción de concurrency

En la guía, el text indica que las queues de envío de GCD definen sus propias agrupaciones de @autoreleasepool y menciona que aún se recomienda definir una a nivel de despacho, pero para NSOperation no se dice nada y el código de ejemplo proporcionado por Apple tampoco muestra el uso de la estructura de @autoreleasepool. El único lugar donde se menciona vagamente a @autoreleasepool en el context de NSOperation está en el Historial de revisiones,

17/07/2012 – Se eliminó información obsoleta sobre el uso del pool de autorelease con operaciones.

Mirando el código de muestra disponible en línea, por ej. http://www.raywenderlich.com/19788/how-to-use-nsoperations-and-nsoperationqueues está haciendo uso de @autoreleasepool en las implementaciones de objects basados ​​en NSOperations, por ejemplo:

@implementation ImageDownloader - (void)main { @autoreleasepool { ... } } @end 
  1. ¿Cómo debo implementar objects de NSOperation modernos?
  2. ¿A qué se refiere la actualización de Apple a partir de 2012-07-17?

Si está derivando de NSOperation e implementando el método main , no necesita configurar un grupo de autorelease. La implementación por defecto del método de start empuja un NSAutoReleasePool , llama main y luego aparece el NSAutoReleasePool . Lo mismo ocurre con NSInvocationOperation y NSBlockOperation , que comparten la misma implementación del método de start .

Lo siguiente es un desassembly abreviado del método de start para NSOperation . Tenga en count las llamadas a NSPushAutoreleasePool, luego una llamada a main seguida de una llamada a 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 

Aquí hay una instantánea de algún código de ejemplo ejecutándose

  1. MyObj se asigna en el método main y me aseguro de que el object debe ser autoelevado
  2. main devuelve a _start , y la siguiente image muestra un rastreo de stack con MyObj dealloc siendo invocado por el grupo de autorelease actual, apareció dentro de _start

La pila de llamadas que muestra el objeto se libera cuando se llama NSPopAutoreleasePool

Como reference, este es el código de ejemplo que utilicé para verificar el comportamiento:

 #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 gestiona de forma similar los sets de autorelease para las queues de envío, según la Guía de progtwigción de la concurrency :

Si su bloque crea más de unos pocos objects Objective-C, es posible que desee include partes del código de su bloque en un bloque @autorelease para manejar la gestión de memory de esos objects. Aunque las queues de envío de GCD tienen sus propias agrupaciones de autorelease, no garantizan cuándo se drenan esas agrupaciones. Si su aplicación está limitada por la memory, crear su propia agrupación autorelease le permite liberar la memory para objects autoelegidos a intervalos más regulares.