Проблема асинхронной загрузки содержимого ScrollView - PullRequest
2 голосов
/ 27 апреля 2010

У меня есть UIScrollView с большим количеством UIImageView внутри. В методе loadView я назначаю некоторое временное изображение для каждого из подвидов изображений UIImageView и запускает несколько потоков для асинхронной загрузки изображений из Интернета. Каждый поток загружает и присваивает изображения следующим образом:

    NSData  *data   = [NSData dataWithContentsOfURL:URL];
    UIImage *img    = [UIImage imageWithData:data];
    img_view.image  = img;

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

Что я пытался сделать:

  1. Вызвать sleep () в теме загрузки - не помогает.
  2. Вызовите setNeedsDisplay для каждого ImageView внутри ScrollView и для ScrollView - не помогает.

Что не так? Спасибо.

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

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

Ответы [ 2 ]

1 голос
/ 28 апреля 2010

Я бы не рекомендовал использовать потоки для этого использования и использовать асинхронный API для извлечения данных в сети.

NSData  *data   = [NSData dataWithContentsOfURL:URL];

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

Я бы использовал библиотеку ASIHTTP или NSURLConnection для доступа к вашим данным и выполнял все ваши обновления в одном потоке. API-интерфейс немного изучен, но он на существенно меньше, чем правильное управление потоками. Я бы настоятельно рекомендовал бы библиотеку ASIHTTP, она просто потрясающая. Вы можете установить делегат запроса для виджета прогресса и регулировать ваше соединение для использования на периферии.

0 голосов
/ 27 апреля 2010

Привет, Newbee (без фан-намерения)

Ситуация, которую вы описываете, звучит как кандидат на NSOperation и NSOperationQueue Вы можете просто «загрузить» все из этих методов и заставить их выяснить, как лучше чтобы получить картину. Если вы продолжаете создавать новые потоки, то в какой-то момент вы теряете преимущества многопоточности, т. Е. Накладные расходы растут для каждого потока, а процессорного времени остается слишком много.

Начните с сортировки списка URL-адресов для изображений так, чтобы самые дальние от пользователя (в смысле scrollView) загружались в последнюю очередь, затем начинайте добавлять операцию загрузки в NSOperationQueue и затем запускать операцию. Эти классы затем уравновесят ситуацию и сэкономят вам кучу кода на логику, чтобы иметь дело со сценариями, которые могут возникнуть.

Я нашел это полезным несколько недель назад: Руководство по эксплуатации NSO

Маркус Зарра излагает хороший простой пример, с чего можно начать.

РЕДАКТИРОВАТЬ: К сожалению ... и ответить на ваш вопрос :), если это не приводит к обновлению ваших фотографий, то вам может потребоваться отправить специальное сообщение "обновление", когда операция будет завершена. Если это большая часть вашего приложения, я бы порекомендовал вам создать PictureObject и переместить в него функциональность. Таким образом, при добавлении PictureObject вы создаете его экземпляр с помощью URL-адреса, и он отображает фиктивную картинку в качестве своего вида. Когда вы передаете этот PictureObject вашему NSOperation, который получает его URL, загружает изображение и устанавливает его в PictureObject. Таким образом, он полностью асинхронен, и вам не нужно иметь дело с циклами или проверкой загрузки изображения и т. Д. И т. Д. Надеюсь, это имеет смысл.

...