GCD и асинхронный NSURLConnection

Я написал пользовательский загрузчик классов, из которого можно разгрузить отдельные классы без GCing загрузчика классов. Jar Class Loader

24
задан bandejapaisa 18 January 2012 в 22:43
поделиться

2 ответа

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

Итак, как вы решаете это? Есть разные варианты для размышления. Я могу перечислить несколько, и я уверен, что другие перечислят больше.

1 - Здесь вы можете использовать синхронное соединение. Одним из недостатков является то, что вы не получите обратные вызовы для аутентификации, перенаправления, кэширования и т. Д. (Все обычные недостатки синхронных соединений.) Кроме того, каждое соединение, конечно, будет блокировать поток на некоторый период времени, так что если вы делаете Многие из них могут потенциально блокировать несколько потоков одновременно, что дорого.

2 - Если ваше соединение простое и вы используете iOS5, то вы можете использовать этот метод:

+ (void)sendAsynchronousRequest:(NSURLRequest *)request
                          queue:(NSOperationQueue*) queue
              completionHandler:(void (^)(NSURLResponse*, NSData*, NSError*))

Это запустит асинхронное соединение, а затем позволит вам указать обработчик завершения (для успеха или неудачи) и a NSOperationQueue, для которого вы хотите, чтобы этот блок был запланирован.

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

3 - Другой вариант для iOS5 - установить очередь для всех обратных вызовов делегата :

- (void)setDelegateQueue:(NSOperationQueue*) queue NS_AVAILABLE(10_7, 5_0);

Если вы используете это тогда все методы делегата будут выполняться в контексте любого указанного вами NSOperationQueue. Так что это похоже на вариант № 2, ожидайте, что теперь вы получите все методы делегата для обработки аутентификации, перенаправления и т. Д.

4 - Вы можете настроить свой собственный поток, которым вы управляете специально для управления этими соединениями. И при настройке этого потока вы настраиваете runloop соответствующим образом. Это хорошо работает в iOS4 и 5 и, очевидно, дает вам все обратные вызовы делегатов, которые вы хотите обработать

5 - вы можете подумать о том, какие части вашей асинхронной обработки соединений являются ] действительно мешает вашему интерфейсу. Как правило, установление соединения или получение обратных вызовов делегатов не так уж и дорого. Дорогие (или неопределенные) затраты часто связаны с обработкой данных, которые вы собираете в конце. Вопрос, который нужно задать, заключается в том, действительно ли вы экономите время, планируя блок в какой-то очереди, чтобы просто запустить асинхронное соединение, которое немедленно разорвется и все равно выполнит свою работу в другом потоке?

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

Так что-то вроде этого:

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {      
        // go ahead and receive this message on the main thread
        // but then turn around and fire off a block to do the real expensive work

        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

         // Parse the data we've been collecting

        });

    }

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

37
ответ дан Firoze Lafeer 18 January 2012 в 22:43
поделиться

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

Если вы хотите вернуть свои данные в основной поток, вы можете вложить асинхронный вызов после извлечения данных:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"www.stackoverflow.com"]];
    NSURLResponse *response;
    NSError *error;
    NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
    if (error) {
        // handle error
        return;
    }
    dispatch_async(dispatch_get_main_queue(), ^{
        // do something with the data
    });
});

Но почему бы не использовать встроенную асинхронную поддержку NSURLConnection? Вам нужен NSOperationQueue, но если вы делаете много сетевых извлечений, то это все равно путь:

NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"www.stackoverflow.com"]];
[NSURLConnection sendAsynchronousRequest:request
                                   queue:self.queue // created at class init
                       completionHandler:^(NSURLResponse *response, NSData *data, NSError *error){
                           // do something with data or handle error
                       }];

Лично я использую библиотеку, такую ​​как AFNetworking или ASIHTTPRequest, чтобы сделать работу в сети еще проще, и обе поддерживают блоки (первый использует GCD и немного более современен).

3
ответ дан rich.e 18 January 2012 в 22:43
поделиться