tldr: ImagedNamed jest w porządku. Dobrze radzi sobie z pamięcią. Użyj go i przestań się martwić.
Edytuj listopad 2012 : Zwróć uwagę, że to pytanie pochodzi z iOS 2.0! Od tego czasu wymagania dotyczące obrazu i obsługa znacznie się zmieniły. Retina powiększa obrazy i ładuje je nieco bardziej skomplikowane. Dzięki wbudowanej obsłudze obrazów iPada i siatkówki, z pewnością powinieneś używać ImageNamed w swoim kodzie. Teraz, dla dobra potomnych:
Wątek siostra na forum jabłko Dev otrzymał jakieś lepsze ruchu. W szczególności Rincewind dodał trochę autorytetu.
W systemie iPhone OS 2.x występują problemy, w których plik imageNamed: cache nie był czyszczony nawet po ostrzeżeniu dotyczącym pamięci. W tym samym czasie + imageNamed: zyskał wiele zastosowań nie ze względu na pamięć podręczną, ale ze względu na wygodę, która prawdopodobnie powiększyła problem bardziej niż powinien.
ostrzegając, że
Jeśli chodzi o prędkość, istnieje ogólne niezrozumienie tego, co się dzieje. Największą rzeczą, jaką robi + imageNamed: jest dekodowanie danych obrazu z pliku źródłowego, co prawie zawsze znacznie zawyża rozmiar danych (na przykład plik PNG o rozmiarze ekranu może zużywać kilkadziesiąt KB podczas kompresji, ale zajmuje ponad pół MB zdekompresowany - szerokość * wysokość * 4). Natomiast + imageWithContentsOfFile: dekompresuje ten obraz za każdym razem, gdy potrzebne są dane obrazu. Jak możesz sobie wyobrazić, jeśli potrzebujesz danych obrazu tylko raz, nic tutaj nie wygrywasz, poza tym, że wersja obrazu przechowywana w pamięci podręcznej kręci się w pobliżu i prawdopodobnie dłużej niż potrzebujesz. Jeśli jednak masz duży obraz, który musisz często przerysowywać, istnieją alternatywy, chociaż przede wszystkim zalecałbym unikanie przerysowywania tego dużego obrazu :).
Jeśli chodzi o ogólne zachowanie pamięci podręcznej, robi ona pamięć podręczną na podstawie nazwy pliku (więc dwa wystąpienia + imageNamed: o tej samej nazwie powinny skutkować odwołaniami do tych samych danych w pamięci podręcznej), a pamięć podręczna będzie rosła dynamicznie, gdy zażądasz więcej obrazów za pośrednictwem + imageNamed :. W systemie iPhone OS 2.xa błąd uniemożliwia zmniejszenie pamięci podręcznej po otrzymaniu ostrzeżenia dotyczącego pamięci.
i
Rozumiem, że + imageNamed: cache powinien uwzględniać ostrzeżenia dotyczące pamięci w systemie iPhone OS 3.0. Przetestuj, kiedy będziesz miał okazję i zgłoś błędy, jeśli okaże się, że tak nie jest.
Więc masz to. imageNamed: nie rozbije okien ani nie zamorduje twoich dzieci. To całkiem proste, ale jest to narzędzie optymalizacyjne. Niestety jest źle nazwany i nie ma odpowiednika, który byłby tak łatwy w użyciu - stąd ludzie nadużywają go i denerwują się, gdy po prostu wykonuje swoją pracę
Dodałem kategorię do UIImage, aby to naprawić:
// 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 dołączył również przykładowy kod do zbudowania własnej zoptymalizowanej wersji. Nie sądzę, że warto go utrzymać, ale tutaj jest to kompletność.
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);
Wadą tego kodu jest to, że zdekodowany obraz zużywa więcej pamięci, ale renderowanie jest szybsze.