Подтвердить что ты не робот

Является ли @autoreleasepool еще необходимым для современного использования iOS 8 NSOperation?

Ive прочитал Concurrency Руководство по программированию

В руководстве говорится, что очереди отправки GCD определяют свои пулы @autoreleasepool и упоминают, что по-прежнему рекомендуется определять один на уровне отправки, но для NSOperation ничего не сказано, а пример кода, предоставленный Apple, также не показать использование структуры @autoreleasepool. Единственное место, где @autoreleasepool смутно упоминается в контексте NSOperation, находится в Истории изменений,

2012-07-17 - Удалена устаревшая информация об использовании пула автозаполнения с операциями.

Взгляд на образец кода, доступный онлайн, например. http://www.raywenderlich.com/19788/how-to-use-nsoperations-and-nsoperationqueues использует @autoreleasepool в реализации объектов, основанных на NSOperations, например:

@implementation ImageDownloader

- (void)main {
    @autoreleasepool {
      ...
    }
}     
@end
  • Как я могу реализовать современные объекты NSOperation?
  • Какое обновление Apple имеет в виду от 2012-07-17?
4b9b3361

Ответ 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

call stack showing object is released when NSPopAutoreleasePool is called

Для справки, это пример кода, который я использовал для проверки поведения:

#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 имеют свои собственные пулы автоопределений, они не дают никаких гарантий относительно того, когда эти пулы сливаются. Если ваше приложение ограничено памятью, создание собственного пула автозапуска позволяет вам освобождать память для автореализованных объектов с более регулярными интервалами.