Метод с блоками внутри NSOperation - как это работает? - PullRequest
1 голос
/ 31 марта 2012

Я работаю над проектом iOS, который должен работать с iOS4. У меня есть NSOperationQueue, и я добавляю операцию. Основной метод операции выглядит примерно так:

-(void)main 
{
    [self.client getStuffSuccess:^(Stuff *s) {
        //Do something on success
    } failure:^(NSError *error) {
        //Do something on failure
    }
}

Код внутри блока будет вызываться только тогда, когда getStuff вызывает успех или неудачу. Я думал, что в это время моя операция будет удалена из NSOperationQueue и блок не будет вызван. Однако, я проверил это, и блок был фактически назван. Он вызывается независимо от того, вызывает ли клиент блок успеха в dispatch_get_main_queue или в потоке, который его вызвал - в данном случае операция выше.

Перед вызовом блока метод isFinished фактически возвращает true (я переопределил метод isFinished и проверил значение), поэтому кто-то может объяснить мне, как это возможно, что блок вызывается?

Я спрашиваю все это, потому что, хотя это прекрасно работает для одного вызова, когда я добавляю его в цикле из нескольких сотен итераций, я получаю EXC_BAD_ACCESS, и понимание вышеизложенного может помочь мне в отладке.

Ответы [ 3 ]

1 голос
/ 31 марта 2012

Код внутри блока будет вызываться только тогда, когда getStuff вызывает успех или неудачу.Я думал, что в это время моя операция будет удалена из NSOperationQueue и блок не будет вызван.

Что заставляет вас в это верить.Блок - это закрытие, автономный блок кода.Он не полагается на существование какого-либо другого объекта (в данном случае NSOperation) для того, чтобы существовать.Вы можете хотеть , чтобы он полагался на этот другой объект, но это зависит от вас.В идеале я бы сделал getStufSuccess: fail: синхронный.Если вы не можете, вы можете использовать NSCondition или вызвать методы NSRunLoop, чтобы дешево заблокировать поток, пока он не будет завершен.

Вам также необходимо рассмотреть безопасность потоков здесьВозможно, ваша проблема не связана с удалением операции, но ваш блок делает что-то не поточно-ориентированное.

0 голосов
/ 01 апреля 2012

Поскольку getStuffSuccess: сбой асинхронный, вам нужно использовать параллельную операцию.Вот полезное сообщение в блоге: http://www.dribin.org/dave/blog/archives/2009/05/05/concurrent_operations/

0 голосов
/ 31 марта 2012

Если ваш -getStuffSuccess:failure не блокирует поток (т. Е. Метод является асинхронным), тогда ваш -main завершится, и ваша операция Queue может освободить вашу операцию до вызова блоков успеха или сбоя. Вы можете заблокировать поток, добавив:

while(notProcessed){
    sleep(0.1);
    //Make sure your success and failure functions update notProcessed BOOL
}

так что main никогда не завершится, пока у вас не было возможности вызвать закрытие. Или просто используйте синхронный метод. Обычно это нормально, потому что вы все равно не будете в потоке пользовательского интерфейса.

...