2016-03-31 3 views
7

У меня есть приложение, которое показывает «полноэкранные карты» в UICollectionView, как Tinder. Карта содержит изображение и текст. Я загружал изображение, используя метод SDWebImagesd_setImageWithURL в ячейке UICollectionView.Изображение Предварительная загрузка в iOS

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

func startImagePreloadingOperationForIndex(index:Int) 
{ 
    let numberOfImagesToBePreloadedOnEachSide = 20 
    var previousIndex = index - numberOfImagesToBePreloadedOnEachSide 
    var nextIndex = index + numberOfImagesToBePreloadedOnEachSide 

    if previousIndex < 0 
    { 
     previousIndex = 0 
    } 
    if nextIndex >= currentNewsCollection.count 
    { 
     nextIndex = currentNewsCollection.count - 1 
    } 

    if previousIndex >= nextIndex || currentNewsCollection.isEmpty 
    { 
     return 
    } 
    let arrayOfNewsStories = currentNewsCollection[previousIndex...nextIndex] 

    let arrayOfImageURLs = arrayOfNewsStories.map({ ImageUtility.getImageStringForNewsStory($0) }) 

    SDWebImagePrefetcher.sharedImagePrefetcher().prefetchURLs(arrayOfImageURLs, progress: { (x, y) -> Void in 
     }) { (x, y) -> Void in 
    } 
} 

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

Это лучшее решение, так как теперь я предварительно загружаю изображения, когда пользователь находится на карте. Однако это параллельная очередь. Это означает, что изображение нет. index + 20 может быть загружен до текущего изображения, и пользователю может потребоваться дождаться изображения. Также приложение становится немного отсталым, если пользователь прокручивает более 50 карт, а использование памяти также продолжает расти.

Может ли кто-нибудь предложить улучшения этого или лучшего алгоритма?

Благодаря

ответ

1

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

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

+0

Спасибо, Майкл. Как добавить мою собственную очередь решить проблему, поскольку SDWebImage обеспечивает оптимизированную очередь. Я попытался использовать последовательную очередь, но это оказалось слишком медленным. Я также пытался играть с количеством загружаемых изображений, но это не помогло –

5

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

currentCardImageView.sd_setImageWithURL(url) { (image, error, imageCacheType, url) in 
    // start prefetching here 
} 

Если текущее изображение уже загружено, SDWebImage узнает об этом и извлекает его из кэша.

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

Другое: SDWebImage обладает свойством maxConcurrentOperationCount. Начните с 1, проверьте, увеличьте до 2, проверьте, увеличьте ... и так далее. Пока вы не найдете, что он отстает.

+0

Спасибо @Darko. Это решит проблему только для текущего изображения, не так ли? Я попробовал предварительную выборку только 5 изображений, но это также вызывало проблемы с памятью и задержкой. –

+0

Попробуйте предварительно запрограммировать только один. Насколько велики изображения? И какова обычная скорость сети? – Darko

+0

Изображения размером менее 100 КБ и ожидаемая скорость сети 3G/4G/Wi-Fi –

1

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

Чтобы улучшить производительность, я разработал контроллер уровня 3 для управления запросом на аватар.

Сначала я проверяю NSCache (все самые последние используемые аватары, которые я сохраняю в NSCache, который обрабатывается iOS, поэтому мне не нужно заботиться о выпуске кеш-памяти при необходимости). Вам просто нужно определить несколько параметров для настройки NSCache.

Если аватар не найден на NSCache, я проверяю свой локальный Db (Sqlite), где самые последние используемые аватары сохраняются как поля Blob. Просто помните, что иногда вам нужно выполнить очистку на локальном Db, выпустив старые данные для сохранения памяти устройства.

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

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

Эти оптимизации работают очень хорошо для меня, мое приложение работает светло.

Надеюсь, это может вам помочь.

+0

Спасибо Jorg. Мое решение похоже на двухуровневое решение. SDImageCache является альтернативой NSCache, и я также реализовал очередь как второй уровень. Как добавление слоя SQLite улучшает производительность? –

+0

Привет Rajeev. Я добавил SQLite для таких случаев, как перезагрузка устройства, перезапуск приложения или даже iOS выпустила его из NSCache. В этом случае, без SQLite, приложение должно снова загрузить пропущенные аватары из веб-служб/AWS. Чтобы этого избежать, если аватар уже находится на локальном db (SQLite), приложение не нужно будет загружать его снова. Он просто получит аватар из локального db, сохранит NSCache и вернет изображение в приложение. –

Смежные вопросы