Блокирует ли NSURLConnection основной поток / поток пользовательского интерфейса

Я загружаю изображения в ячейки табличного представления, поскольку они прокручиваются на экран. По причинам UX я начинаю загружать изображения в - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath, Я не жду, пока просмотр таблицы не закончится прокруткой. Когда ячейка табличного представления установлена, я начинаю загружать изображения, которых у меня уже нет. Однако они не загружаются полностью, пока представление таблицы не перестанет двигаться. Как только он перестает двигаться, изображения практически мгновенно загружаются.

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

** РЕДАКТИРОВАТЬ **

Чтобы доказать, что NSURLConnection медленнее, я использовал NSThread для отсоединения нового селектора в другом потоке. Затем я загружаю данные и перезваниваю в главный поток, где создаю UIImage и показываю его в табличном представлении. Этот метод работает НАМНОГО быстрее.

Лично я думаю, что NSURLConnection попадает в цикл обработки событий, где прокрутка UITableView блокирует его.

4 ответа

Прочитайте NSDefaultRunLoopMode против NSRunLoopCommonModes для хорошего объяснения того, почему все уведомления о загрузке делегатов поставлены в очередь, но для загрузки во время прокрутки при использовании основного потока измените это:

NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request
                                                              delegate:self];

к этому:

NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request
                                                              delegate:self
                                                      startImmediately:NO];
[connection scheduleInRunLoop:[NSRunLoop currentRunLoop]
                      forMode:NSRunLoopCommonModes];
[connection start];

Я испытывал эту проблему раньше. Асинхронные методы делегата NSURLConnection не запускаются во время прокрутки scrollView. Хотя загрузка работает в фоновом режиме, ваш основной поток не информируется о новых изображениях. Как и вы, я полагаю, что проблема связана с прокруткой прокрутки во внутреннем NSRunLoop с другим RunLoopMode. Я говорил об этом с сотрудниками Apple, чтобы они посмотрели мой код, но мы не смогли найти решение.

С другой стороны, у Джеффа Ламарша есть этот пост в своем блоге, где он делает то же самое, и он работает, как и ожидалось. Я не смог понять, что он делает по-другому (в основном из-за нехватки времени), но это может стоить посмотреть.

Если вы имеете в виду "NSURLConnection выполняется в основном потоке?", То да, я считаю, что это так. Соединение открывается, и методы делегата выполняются в главном потоке. Я не нашел никакой документации, которая могла бы предложить иначе, и вы можете проверить это путем отладки.

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

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

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

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

Похоже, вы делаете синхронную загрузку.

http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/URLLoadingSystem/Tasks/UsingNSURLConnection.html

Прочтите там и убедитесь, что вы используете асинхронные API

Другие вопросы по тегам