Ответ 1
В действительности проблема заключается не в продолжительности жизни потока, на котором работает ваш блок, а в том, что этот конкретный поток не будет иметь настроенную и запущенную runloop для получения любого из событий, возвращающихся из соединения.
Итак, как вы это решаете? Есть разные варианты, о которых можно подумать. Я могу перечислить несколько, и я уверен, что другие будут перечислять больше.
1. Здесь вы можете использовать синхронное соединение. Один из недостатков заключается в том, что вы не получите обратные вызовы для аутентификации, перенаправления, кэширования и т.д. (Все обычные недостатки синхронных подключений). Плюс каждое соединение, конечно, будет блокировать поток в течение некоторого периода времени, поэтому, если вы делаете многие из них тогда потенциально могут заблокировать сразу несколько потоков, что дорого.
2. Если ваше соединение прост и вы используете iOS5, вы можете использовать этот метод:
+ (void)sendAsynchronousRequest:(NSURLRequest *)request
queue:(NSOperationQueue*) queue
completionHandler:(void (^)(NSURLResponse*, NSData*, NSError*))
Это запустит асинхронное соединение, а затем позволит вам указать обработчик завершения (для успеха или неудачи) и 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
});
}
Опять же, это не является исчерпывающим. Есть много способов справиться с этим, в зависимости от ваших конкретных потребностей здесь. Но я надеюсь, что эти мысли помогут.