Розгортання зображення UIImageNamed: FUD


117

Редагувати Лютий 2014: Зауважте, що це запитання починається з iOS 2.0! З тих пір вимоги до зображення та обробку значно змінилися. Сітківка збільшує зображення і завантажує їх трохи складніше. Маючи вбудовану підтримку зображень iPad та сітківки, ви, звичайно, повинні використовувати ImageNamed у своєму коді .

Я бачу, що багато людей кажуть, що imageNamedце погано, але однакова кількість людей каже, що продуктивність хороша - особливо під час надання UITableViews. Дивіться це питання ТАК, наприклад, цю статтю на iPhoneDeveloperTips.com

UIImage«S imageNamedметод , який використовується для витоку , так що краще всього уникати , але була виправлена в останніх версіях. Я хотів би краще зрозуміти алгоритм кешування, щоб прийняти обґрунтоване рішення про те, де я можу довіряти системі кешування своїх зображень і де мені потрібно пройти зайву милю і зробити це самостійно. Моя поточна базове розуміння, що це просто NSMutableDictionaryз UIImagesпосилання на ім'я файлу. Він стає більшим, а коли пам'яті закінчується, він стає набагато меншим.

Наприклад, хтось точно знає, що кеш зображень позаду imageNamedне відповідає didReceiveMemoryWarning? Мабуть, мабуть, Apple не зробить цього.

Якщо ви маєте детальну інформацію про алгоритм кешування, опублікуйте його тут.


2
я також. Здається, ТАК не так повно геніїв, як я думав.
Рог

Здається, ви витратили певний час на це. Чи проводили ви експерименти, які б показали будь-який негативний вплив UIImage imageNamed з останньою версією какао-сенсорного? Створіть UITableView і додайте багато (багато тисяч) рядків і побачите, чи знижується продуктивність, коли ви показуєте різні зображення в кожному рядку. Можливо, тоді люди можуть коментувати ваші висновки.
stefanB

Власне, я не робив стільки експериментальних дій. Я використовую imageNamed, і хоча мені ще не потрібна оптимізація цього додатка, у мене немає нічого, що я можу прямо вказати на imageNamed як свиню пам’яті. Я вказав на кілька публікацій в блозі, які скаржилися на ImagedNamed тут, і я поставив подібне питання на дошках яблук, які отримали більше дій. Я перекладу резюме та посилання тут, коли матиму час і відчуваю, що це було відповіді, які він отримає.
Рог

Відповіді:


85

tldr: ImagedNamed - це добре. Він добре обробляє пам'ять. Використовуйте його і перестаньте хвилюватися.

Редагувати листопад 2012 року : Зауважте, що це запитання дано iOS 2.0! З тих пір вимоги до зображення та обробку значно змінилися. Сітківка збільшує зображення і завантажує їх трохи складніше. Маючи вбудовану підтримку зображень iPad та сітківки, ви, звичайно, повинні використовувати ImageNamed у своєму коді. Тепер заради нащадків:

Сестра нитку на форумах Apple , Dev отримав кілька краще трафіку. Конкретно Рінсвінд додав певних повноважень.

В iPhone OS 2.x є проблеми, коли кеш imageNamed: кеш не буде очищено навіть після попередження пам'яті. У той же час + imageNamed: отримав багато користі не для кешу, а для зручності, що, ймовірно, збільшило проблему більше, ніж могло бути.

при цьому попереджуючи це

На фронті швидкості існує загальне нерозуміння того, що відбувається. Найголовніше, що має + imageNamed: - це декодування даних зображень із вихідного файлу, що майже завжди значно збільшує розмір даних (наприклад, PNG-файл розміром з екраном може споживати кілька десятків КБ при стисненні, але витрачає понад пів МБ декомпресія - ширина * висота * 4). На відміну від + imageWithContentsOfFile: буде декомпресувати це зображення кожного разу, коли потрібні дані зображення. Як ви можете собі уявити, якщо вам потрібні дані зображення лише один раз, ви нічого тут не виграєте, окрім того, що ви маєте кешовану версію зображення, що висить навколо, і, швидше за все, довше, ніж вам потрібно. Однак якщо у вас є велике зображення, яке потрібно часто перемальовувати, то є альтернативи, хоча одна, яку я рекомендував би в першу чергу, це уникати перемальовування цього великого зображення :).

Що стосується загальної поведінки кешу, він робить кеш, заснований на імені файлу (тому два екземпляри + imageNamed: з тим самим іменем повинні спричинити посилання на ті самі кешовані дані) і кеш буде динамічно зростати, коли ви запитаєте більше зображень через + imageNamed:. На iPhone OS 2.xa помилка запобігає зменшенню кешу при отриманні попередження про пам'ять.

і

Я розумію, що кеш + imageNamed: кеш повинен поважати попередження пам’яті на iPhone OS 3.0. Перевірте це, коли отримаєте шанс і повідомте про помилки, якщо виявите, що це не так.

Отже, там у вас є. imageNamed: не розгромить ваші вікна та не вб’є ваших дітей. Це досить просто, але це інструмент для оптимізації. На жаль, це погано названо, і немає жодного еквівалента, який би настільки простий у використанні - отже, люди надмірно зловживають ним і засмучуються, коли він просто робить свою роботу

Я додав категорію до UIImage, щоб виправити це:

// header omitted
// Before you waste time editing this, please remember that a semi colon at the end of a method definition is valid and a matter of style.
+ (UIImage*)imageFromMainBundleFile:(NSString*)aFileName; {
    NSString* bundlePath = [[NSBundle mainBundle] bundlePath];
    return [UIImage imageWithContentsOfFile:[NSString stringWithFormat:@"%@/%@", bundlePath,aFileName]];
}

Rincewind також включив приклад коду для створення власної оптимізованої версії. Я не можу бачити, що це варто, але це для повноти.

CGImageRef originalImage = uiImage.CGImage;
CFDataRef imageData = CGDataProviderCopyData(
     CGImageGetDataProvider(originalImage));
CGDataProviderRef imageDataProvider = CGDataProviderCreateWithCFData(imageData);
CFRelease(imageData);
CGImageRef image = CGImageCreate(
     CGImageGetWidth(originalImage),
     CGImageGetHeight(originalImage),
     CGImageGetBitsPerComponent(originalImage),
     CGImageGetBitsPerPixel(originalImage),
     CGImageGetBytesPerRow(originalImage),
     CGImageGetColorSpace(originalImage),
     CGImageGetBitmapInfo(originalImage),
     imageDataProvider,
     CGImageGetDecode(originalImage),
     CGImageGetShouldInterpolate(originalImage),
     CGImageGetRenderingIntent(originalImage));
CGDataProviderRelease(imageDataProvider);
UIImage *decompressedImage = [UIImage imageWithCGImage:image];
CGImageRelease(image);

Компроміс із цим кодом полягає в тому, що декодоване зображення використовує більше пам'яті, але візуалізація відбувається швидше.


Здається, що на iOS11 [UIImage imageNamed:] не вилучає зображення з кешу, якщо зображення надходять із каталогу xcasset. Це призводить до збоїв через втрату пам’яті.
Юрай Антас

5

На мій досвід, кеш зображень, створений imageNamed, не відповідає попередженням пам'яті. У мене було два додатки, які були настільки худими, наскільки я міг їх отримати, що стосується управління пам’яттю, але все ще незрозуміло вийшли з ладу через брак пам’яті. Коли я перестав використовувати imageNamed для завантаження зображень, обидва програми стали значно стійкішими.

Я визнаю, що обидва додатки завантажували дещо великі зображення, але нічого, що було б абсолютно незвичним. У першій програмі я просто пропустив кешування, тому що навряд чи користувач повернеться до того ж зображення двічі. По-друге, я створив дуже простий клас кешування, виконуючи саме те, що ви згадали - зберігаючи UIImages у NSMutableDictionary, а потім очищаючи його вміст, якщо я отримав попередження про пам'ять. Якщо imageNamed: кешував таким чином, я не повинен був бачити жодного оновлення продуктивності. Все це працювало на 2.2 - я не знаю, чи є якісь наслідки для цього 3.0.

Ви можете знайти моє інше питання щодо цієї проблеми в моєму першому додатку тут: StackOverflow питання про кешування керування UIImage

Ще одна примітка - InterfaceBuilder використовує imageNamed під обкладинками. Що потрібно пам’ятати, якщо ви зіткнулися з цією проблемою.


Я бачив абсолютно таку ж поведінку, і читання з файлу безпосередньо це вирішило. Також це трапляється, коли я намагаюся завантажити дуже велике зображення - 11456 х 3,226 пікселів, 15 Мб. Моя теорія полягає в тому, що в системі кеш-пам’яті ImageNamed система втрачає частину пам’яті. І в цьому випадку немає вбудованої обробки.
Dogweather
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.