__blocks и размещение объектов в dispatch_sync

Я хотел бы вернуть массив, содержимое которого было установлено во время блока dispatch_sync.

Код, который я обычно видел, выглядит примерно так:

-(NSArray *)getSomeLockedList {

    __block NSArray *resultList;

    dispatch_sync(myQueue, ^{   
       // copy contents of my ivar NSMutableArray into return variable  
       resultList = [ivarContentList copy]; 
    });

    // add auto-release since a 'copy' was done within block
    return [resultList autorelease]; 
}

Если я не делаю копию полного массива, а вместо этого хочу добавить один за другим, могу ли я пропустить «авторелиз» в возвращаемом значении?

-(NSArray *)getSomeLockedList {

    __block NSArray *someResultKeys; // is it ever safe to do the alloc here?

    dispatch_sync(myQueue, ^{       
       someResultKeys = [NSMutableArray array];

    for (id entry in ivarContentList) {

          // do some work on entry instance
          [someResultKeys addObject:entry];     
       }        
    });

    return someResultKeys; // autorelease not necessary?
}

Безопасно ли выделение [массива NSMutableArray] в блоке dispatch_sync для дальнейшего использования результата после завершения стека для этого метода?


person Jonas Anderson    schedule 10.01.2011    source источник


Ответы (2)


Нет, это не безопасно. Проблема заключается в том, что при отправке в очередь любые объекты, которые автоматически освобождаются в этой очереди, будут собраны, когда NSAutoreleasePool этой очереди истощится. Вы не можете контролировать, когда это произойдет. Правильный способ думать об этом — всегда предполагать, что пул автоматического освобождения будет слит в тот момент, когда ваш блок завершит выполнение в очереди.

Правильный способ справиться с этим в вашем случае - использовать

someResultKeys = [[NSMutableArray alloc] init];

в очереди, а затем вызовите [someResultKeys autorelease] после dispatch_sync.

person Lily Ballard    schedule 10.01.2011
comment
Или создайте изменяемый массив перед блоком и просто добавьте в него элементы в блоке. В этом случае someResultsKey не нужно объявлять __block, так как он не будет изменен в блоке. - person Daniel Dickison; 11.01.2011
comment
@Daniel Это, вероятно, лучший способ сделать это в данном конкретном случае. - person Lily Ballard; 11.01.2011

Это делается намного проще, избегая переменной __block, просто написав

NSMutableArray* someResultKeys = [NSMutableArray array];

вне блока. Однако мне интересно узнать о файле dispatch_sync. Вы знаете, что dispatch_sync будет ждать завершения выполнения блока? (А в случае последовательной очереди это означает, что все блоки до ее завершения также завершатся). Есть ли веская причина, по которой вы не вызываете код напрямую?

person gnasher729    schedule 20.03.2014