Мы все знаем о таинственном скрытом кэширующем механизме метода UIImage imageNamed:
. В Apple Справочник класса UIImage в нем говорится:
В ситуациях с низкой памятью данные изображения могут быть очищены от объекта UIImage, чтобы освободить память в системе. Это поведение очистки влияет только на данные изображения, хранящиеся внутри объекта UIImage, а не на сам объект. При попытке нарисовать изображение, данные которого были очищены, объект изображения автоматически перезагружает данные из его исходного файла. Однако этот дополнительный шаг загрузки может привести к небольшому штрафу за производительность.
Фактически, данные изображения не будут "очищены от объекта UIImage, чтобы освободить память в системе", как показывает документация. Вместо этого приложение получает предупреждения о памяти до тех пор, пока оно не перестанет "из-за давления памяти".
РЕДАКТИРОВАТЬ: При использовании обычных ссылок на файлы изображений в вашем проекте Xcode кеширование UIImage отлично работает. Это просто, когда вы переходите к каталогам активов, которые не выпускаются в памяти.
Я реализовал UIScrollView с несколькими UIImageViews для прокрутки длинного списка изображений. При прокрутке следующие изображения загружаются и присваиваются свойству UIImageView image
, удаляя сильную ссылку на ранее сохраненный UIImage.
Из-за механизма кэширования imageNamed:
у меня быстро заканчивается память, и приложение завершается выделенной памятью объемом 170 МБ.
Конечно, существует множество интересных решений для реализации пользовательских механизмов кэширования, включая переопределение метода класса imageNamed:
в категории. Часто вместо этого используется метод класса imageWithContentOfFile:
, который не кэширует данные изображения, как это было предложено разработчиками Apple на WWDC 2011.
Эти решения отлично подходят для обычных файлов изображений, хотя вам нужно получить расширение пути и файла, которое не так элегантно, как мне бы хотелось.
Я использую новые Asset Catalogs, представленные в Xcode 5, однако, чтобы использовать механизмы условной загрузки изображений в зависимости от устройства и эффективного хранения файлов изображений. На данный момент, похоже, нет прямого способа загрузки изображения из каталога активов без использования imageNamed:
, если только я не вижу очевидного решения.
Вы, ребята, вычислили механизм кэширования UIImage с каталогами ресурсов?
Я хотел бы реализовать категорию в UIImage, подобную следующей:
static NSCache *_cache = nil;
@implementation UIImage (Caching)
+ (UIImage *)cachedImageNamed:(NSString *)name {
if (!_cache) _cache = [[NSCache alloc] init];
if (![_cache objectForKey:name]) {
UIImage *image = ???; // load image from Asset Catalog without internal caching mechanism
[_cache setObject:image forKey:name];
}
return [_cache objectForKey:name];
}
+ (void)emptyCache {
[_cache removeAllObjects];
}
@end
Еще лучше было бы получить больше контроля над внутренним кешем UIImage
и возможностью очистки данных изображения в условиях низкой памяти, как описано в документации при использовании Каталогов активов.
Спасибо за чтение, и я с нетерпением жду ваших идей!