проблема с dispatch_async и асинхронным запросом - PullRequest
5 голосов
/ 27 марта 2012

Итак, первый вопрос: как dispatch_async определяет, какой поток использовать?просто выбирает это случайно?Мне нужно выполнить некоторые синтаксические и основные операции с данными, поэтому я не хочу блокировать поток пользовательского интерфейса и использовать dispatch_async, но после этого я отправляю NSURLRequest для получения дополнительных данных, и обратный вызов никогда не вызывается (возможно, потому чтонить уже мертва).

Так какой же хороший способ сделать это?И я не могу использовать

sendAsynchronousRequest:queue:completionHandler: 

, потому что операционная система развертывания - 4. Сейчас я просто отправляю запрос внутри

dispatch_async(dispatch_get_main_queue(), ^{
});

, который находится внутри блока dispatch_async(myQueue), который выполняет весь анализ исохранение в основные данные.Но мне это не кажется правильным, я имею в виду, что должен быть способ использовать dispatch_async и сказать, чтобы он не убивал шаг, верно?Потому что использование запросов синхронизации не вариант.

Ответы [ 3 ]

12 голосов
/ 27 марта 2012

Итак, первый вопрос: как dispatch_async определяет, какой поток использовать?

Вы не должны думать о потоках при использовании GCD. Это все решается за кулисами для вас. Вы думаете о очередях , которые вы передаете dispatch_async вместе с блоком для выполнения. Очередь GCD как бы отображается в потоке, но вам не нужно беспокоиться о том, что происходит за кулисами - GCD справится со всем этим для вас.

Что касается вашего кода, который, как я полагаю, выглядит примерно так:

dispatch_async(myQueue, ^{
    // Do some stuff off the main queue

    dispatch_async(dispatch_get_main_queue(), ^{ 
        // Do something with the UI
    });
});

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

Я думаю, вы также спрашиваете, почему при использовании NSURLRequest в асинхронной диспетчеризации вы видите, что он никогда не вызывает обратный вызов. Это будет связано с тем, что он тесно связан с текущим циклом выполнения, и если вы в данный момент находитесь в фоновом потоке (на котором будет работать ваш myQueue), то этот цикл выполнения больше не будет выполняться, пока другой блок не будет помещен в очередь. Таким образом, ваш обратный вызов никогда не запускается.

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

3 голосов
/ 27 марта 2012

Когда вы используете sendAsynchronousRequest:... в блоке, блок завершится до того, как будет запущен обратный вызов асинхронного запроса.

Поскольку вы уже находитесь в фоновом потоке, как насчет использования синхронного метода в этом потоке для получения ваших данных - +[NSURLRequest sendSynchronousRequest:returningResponse:error:], или даже проще, +[NSData dataWithContentsOfURL:].

Вы можете вызывать их в блоке, работающем в фоновом потоке, и блок не будет выполняться до тех пор, пока вызов не будет завершен.Затем вы можете обновить свой интерфейс, перезвонив в основную очередь:

dispatch_async(yourQueue, ^{
    // Do some stuff

    NSData * fetchedData = [NSData dataWithContentsOfURL: someURL];

    // Do some more stuff with the data

    dispatch_async(dispatch_get_main_queue(), ^{
       // Do some stuff on the main queue
    }
});
0 голосов
/ 08 ноября 2013

Вы правы, проблема в том, что поток мертв, потому что NSURLConnection не будет поддерживать его в течение жизни.Соединение будет сброшено, когда оно вернется.Вы можете явно поддерживать поток с помощью некоторой темной магии;) и освободить поток, когда закончите.В этом случае, установив для _isFinishedLoading значение true в случае успеха или в случае ошибки.

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

NSURLConnection* connection = [NSURLConnection connectionWithRequest:urlRequest delegate:self];
[connection start];
NSRunLoop *runloop = [NSRunLoop currentRunLoop];
_isFinishedLoading = NO;
while (!_isFinishedLoading)
{
    [runloop runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
}
...