Я пытаюсь повысить производительность моего приложения для iPhone с интенсивным использованием изображений, используя дисковый кэш изображений вместо того, чтобы работать по сети.Я смоделировал мой кэш изображений после SDImageCache (http://github.com/rs/SDWebImage/blob/master/SDImageCache.m), и почти такой же, но без асинхронных операций ввода / вывода кеша.
У меня есть несколько представлений прокрутки и таблиц, которые загружают эти изображения асинхронноЕсли изображение находится на диске, оно загружается из кэша изображений, в противном случае выполняется сетевой запрос и последующий результат сохраняется в кэше.
Проблема, с которой я сталкиваюсь, заключается в том, что при прокруткепри просмотре с прокруткой или просмотре таблицы наблюдается заметная задержка при загрузке изображения с диска. В частности, анимация перехода с одной страницы на другую в представлении с прокруткой имеет небольшую задержку в середине перехода.
Я пытался исправить это следующим образом:
- Использование объектов NSOperationQueue и NSInvocationOperation для выполнения запросов на доступ к диску (так же, как SDImageCache), но это не помогает сзапаздывает на всех.
- Настройка кода контроллера представления прокрутки, чтобы он загружал изображения только при прокруткепросмотр больше не прокручиваетсяЭто означает, что доступ к диску срабатывает только тогда, когда представление прокрутки перестает прокручиваться, но если я сразу пытаюсь перейти к следующей странице, я могу заметить задержку при загрузке изображения с диска.
IsЕсть ли способ улучшить доступ к диску или уменьшить его влияние на пользовательский интерфейс?
Обратите внимание, что я уже кэширую изображения в памяти.Поэтому, когда все загружено в память, пользовательский интерфейс становится приятным и отзывчивым.Но при запуске приложения или при отправке предупреждений о нехватке памяти многие из этих задержек пользовательского интерфейса возникают при загрузке изображений с диска.
Ниже приведены соответствующие фрагменты кода.Я не думаю, что я делаю что-то необычное или сумасшедшее.Эта задержка не выглядит заметной на iPhone 3G, но она довольно заметна на iPod Touch 2-го поколения.
Код кэширования изображения:
Вотсоответствующий фрагмент моего кода кэширования изображений.Довольно просто.
- (BOOL)hasImageDataForURL:(NSString *)url {
return [[NSFileManager defaultManager] fileExistsAtPath:[self cacheFilePathForURL:url]];
}
- (NSData *)imageDataForURL:(NSString *)url {
NSString *filePath = [self cacheFilePathForURL:url];
// Set file last modification date to help enforce LRU caching policy
NSMutableDictionary *attributes = [NSMutableDictionary dictionary];
[attributes setObject:[NSDate date] forKey:NSFileModificationDate];
[[NSFileManager defaultManager] setAttributes:attributes ofItemAtPath:filePath error:NULL];
return [NSData dataWithContentsOfFile:filePath];
}
- (void)storeImageData:(NSData *)data forURL:(NSString *)url {
[[NSFileManager defaultManager] createFileAtPath:[self cacheFilePathForURL:url] contents:data attributes:nil];
}
Код контроллера представления прокрутки
Вот соответствующий фрагмент кода, который я использую для отображения изображений в моих контроллерах представления прокрутки.
- (void)scrollViewDidScroll:(UIScrollView *)theScrollView {
CGFloat pageWidth = theScrollView.frame.size.width;
NSUInteger index = floor((theScrollView.contentOffset.x - pageWidth / 2) / pageWidth) + 1;
[self loadImageFor:[NSNumber numberWithInt:index]];
[self loadImageFor:[NSNumber numberWithInt:index + 1]];
[self loadImageFor:[NSNumber numberWithInt:index - 1]];
}
- (void)loadImageFor:(NSNumber *)index {
if ([index intValue] < 0 || [index intValue] >= [self.photoData count]) {
return;
}
// ... initialize an image loader object that accesses the disk image cache or makes a network request
UIView *iew = [self.views objectForKey:index];
UIImageView *imageView = (UIImageView *) [view viewWithTag:kImageViewTag];
if (imageView.image == nil) {
NSDictionary *photo = [self.photoData objectAtIndex:[index intValue]];
[loader loadImage:[photo objectForKey:@"url"]];
}
}
Объект загрузчика изображений - это просто легкий объект, который проверяет дисковый кэш и решает, извлекать ли изображение с диска или из сети.После этого он вызывает метод на контроллере представления прокрутки для отображения изображения:
- (void)imageLoadedFor:(NSNumber *)index image:(UIImage *)image {
// Cache image in memory
// ...
UIView *view = [self.views objectForKey:index];
UIImageView *imageView = (UIImageView *) [view viewWithTag:kImageViewTag];
imageView.contentMode = UIViewContentModeScaleAspectFill;
imageView.image = image;
}
ОБНОВЛЕНИЕ
Я экспериментировал с приложением и отключилкэш изображений и вернулся к всегда делать сетевые запросы.Похоже, простое использование сетевых запросов для извлечения изображений также вызывает то же отставание при прокрутке представлений прокрутки и представлений таблицы!То есть, когда сетевой запрос завершается и изображение отображается на странице просмотра прокрутки или в ячейке таблицы, пользовательский интерфейс немного отстает и имеет задержку в несколько секунд, пока я пытаюсь его перетащить.
Похоже, что задержка становится более заметной при использовании дискового кэша, поскольку задержка всегда происходит непосредственно при переходе на другую страницу.Возможно, я делаю что-то не так при назначении загруженного изображения соответствующему UIImageView?
Кроме того - я пробовал использовать маленькие изображения (миниатюры 50x50), и лаг, кажется, улучшается.Таким образом, кажется, что снижение производительности происходит из-за загрузки большого изображения с диска или загрузки большого изображения в объект UIImage.Я предполагаю, что одним из улучшений было бы уменьшение размера изображений, загружаемых в представления прокрутки и представления таблиц, что я и планировал сделать, тем не менее.Однако я просто не понимаю, как другие приложения, интенсивно использующие фотографии, могут отображать фотографии с высоким разрешением в виде с прокруткой без проблем с производительностью при переходе на диск или по сети.