UIImage imageNamed'in yazımını kaldırma: FUD


117

Şubat 2014'ü Düzenle: Bu sorunun iOS 2.0'dan kalma olduğunu unutmayın! Görüntü gereksinimleri ve kullanımı o zamandan beri çok değişti. Retina, görüntüleri büyütür ve biraz daha karmaşık hale getirir. İPad ve retina görüntüleri için yerleşik destekle , kodunuzda kesinlikle ImageNamed kullanmalısınız .

Pek çok insanın imageNamedkötü olduğunu ancak eşit sayıda insanın performansın iyi olduğunu söylediğini görüyorum - özellikle de UITableViews'yi oluştururken. Bkz bu SO soru örneğin veya bu makaleyi iPhoneDeveloperTips.com üzerinde

UIImage'ın imageNamedyöntemi sızıntı yapmak için kullanıldı, bu yüzden en iyi şekilde kaçınıldı, ancak son sürümlerde düzeltildi. Görüntülerimi önbelleğe alması için sisteme nerede güvenebileceğim ve fazladan yol kat edip bunu kendim yapmam gerektiği konusunda mantıklı bir karar vermek için önbelleğe alma algoritmasını daha iyi anlamak istiyorum. Şu anki temel anlayışım, bunun dosya adıyla referans NSMutableDictionaryverilmesinin basit olmasıdır UIImages. Büyüyor ve hafıza bittiğinde çok daha küçülüyor.

Örneğin, arkadaki görüntü önbelleğinin imageNamedyanıt vermediğinden emin olan var didReceiveMemoryWarningmı? Apple'ın bunu yapmaması pek olası görünmüyor.

Önbelleğe alma algoritmasıyla ilgili herhangi bir fikriniz varsa, lütfen buraya gönderin.


2
ben de. Görünüşe göre SO, düşündüğüm kadar dahilerle dolu değil.
Rog

Bunu araştırmak için biraz zaman harcamış gibisin. En son cocoa-touch sürümüyle UIImage imageNamed'in olumsuz etkisini gösterecek herhangi bir deney yaptınız mı? Bir UITableView oluşturun ve çok sayıda (binlerce) satır ekleyin ve her satırda farklı bir görüntü gösterdiğinizde performansın düşüp düşmediğine bakın. Belki o zaman insanlar bulgularınız hakkında yorum yapabilir.
stefanB

Aslında o kadar çok deney yapmadım. İmageNamed'i kullanıyorum ve bu uygulamayı henüz hafızamda optimize etmememe rağmen, doğrudan imageNamed'e bir bellek domuzu olarak işaret edebileceğim hiçbir şey yok. Burada imagedNamed hakkında şikayet eden birkaç blog gönderisine işaret ettim ve daha fazla aksiyon alan elma panolarında benzer bir soru sordum. Zamanım olduğunda ve alacağı yanıtları aldığımı hissettiğimde buraya bir özet ve bağlantı göndereceğim.
Rog

Yanıtlar:


85

tldr: ImagedNamed iyidir. Hafızayı iyi idare eder. Kullan ve endişelenmeyi bırak.

Kasım 2012'yi Düzenle : Bu sorunun iOS 2.0'dan kalma olduğunu unutmayın! Görüntü gereksinimleri ve kullanımı o zamandan beri çok değişti. Retina, görüntüleri büyütür ve biraz daha karmaşık hale getirir. İPad ve retina görüntüleri için yerleşik destekle, kodunuzda kesinlikle ImageNamed kullanmalısınız. Şimdi, gelecek nesillerin aşkına:

Kardeş parçacığı Apple Dev Forumlar bazı iyi trafik almış. Özellikle Rincewind biraz yetki ekledi.

İPhone OS 2.x'te, bir bellek uyarısından sonra bile imageNamed: önbelleğin temizlenemeyeceği sorunlar var. Aynı zamanda + imageNamed: önbellek için değil, kolaylık sağlamak için çokça kullanıldı, bu da sorunu olması gerekenden daha fazla büyüttü.

uyarırken

Hız cephesinde, neler olduğuna dair genel bir yanlış anlama var. + İmageNamed'in yaptığı en büyük şey, kaynak dosyadaki görüntü verilerinin kodunu çözmektir; bu, neredeyse her zaman veri boyutunu önemli ölçüde artırır (örneğin, ekran boyutundaki bir PNG dosyası sıkıştırıldığında birkaç düzine KB tüketebilir, ancak yarım MB'den fazla tüketir. sıkıştırılmış - genişlik * yükseklik * 4). Buna karşılık + imageWithContentsOfFile: görüntü verilerine her ihtiyaç duyulduğunda bu görüntüyü açar. Tahmin edebileceğiniz gibi, görüntü verilerine yalnızca bir kez ihtiyacınız varsa, burada görüntünün önbelleğe alınmış bir sürümünün etrafta asılı kalması ve muhtemelen ihtiyacınız olandan daha uzun süre olması dışında hiçbir şey kazanamazsınız. Bununla birlikte, sık sık yeniden çizmeniz gereken büyük bir resminiz varsa, alternatifler de vardır, ancak öncelikle tavsiye edeceğim şey o büyük resmi yeniden çizmekten kaçınmaktır :).

Önbelleğin genel davranışıyla ilgili olarak, dosya adına göre önbelleğe alır (bu nedenle, aynı ada sahip iki + imageNamed örneği, aynı önbelleğe alınmış verilere başvurularla sonuçlanmalıdır) ve önbellek, aracılığıyla daha fazla görüntü talep ettikçe dinamik olarak büyür. + imageNamed :. İPhone OS 2.xa bug, bir bellek uyarısı alındığında önbelleğin küçülmesini engeller.

ve

Anladığım kadarıyla + imageNamed: önbelleğin iPhone OS 3.0'daki bellek uyarılarına uyması gerekiyor. Şansınız olduğunda test edin ve durumun böyle olmadığını anlarsanız hataları bildirin.

İşte orada var. imageNamed: camlarınızı kırmaz veya çocuklarınızı öldürmez. Oldukça basit ama bir optimizasyon aracı. Ne yazık ki kötü bir şekilde adlandırılmış ve kullanımı kolay bir muadili yok - bu yüzden insanlar onu aşırı kullanıyor ve sadece işini yaptığında üzülüyor

Bunu düzeltmek için UIImage'a bir kategori ekledim:

// 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 ayrıca kendi optimize edilmiş sürümünüzü oluşturmak için bazı örnek kodlar içeriyordu. Bakıma değer olduğunu göremiyorum ama burada tamlık için.

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);

Bu kodla değiş tokuş, kodu çözülen görüntünün daha fazla bellek kullanması, ancak oluşturmanın daha hızlı olmasıdır.


Görünüşe göre iOS11'de, xcasset kataloğundan görüntüler geliyorsa [UIImage imageNamed:] önbellekten görüntüleri çıkarmıyor. Bu, bellek yetersizliği nedeniyle çökmelere neden olur.
Juraj Antas

5

Deneyimlerime göre, imageNamed tarafından oluşturulan görüntü önbelleği bellek uyarılarına yanıt vermiyor. Mem yönetimine kadar alabildiğim kadar yalın olan, ancak mem eksikliğinden dolayı hala açıklanamaz bir şekilde çökmekte olan iki uygulamam vardı. Görüntüleri yüklemek için imageNamed'i kullanmayı bıraktığımda, her iki uygulama da önemli ölçüde daha kararlı hale geldi.

Her iki uygulamanın da biraz büyük resimler yüklediğini kabul ediyorum, ancak tamamen sıra dışı bir şey olmayacak. İlk uygulamada, önbelleğe almayı tamamen atladım çünkü bir kullanıcının aynı görüntüye iki kez geri dönme olasılığı düşüktü. İkincisi, tam da bahsettiğiniz şeyi yaparak gerçekten basit bir önbelleğe alma sınıfı oluşturdum - UIImages'ı bir NSMutableDictionary içinde tutmak ve ardından bir bellek uyarısı alırsam içeriğini temizlemek. İmageNamed: böyle önbelleğe alacak olsaydı, herhangi bir performans yükseltmesi görmemeliydim. Bunların hepsi 2.2'de çalışıyordu - bunun 3.0 çıkarımı var mı bilmiyorum.

Bu sorunla ilgili diğer sorumu ilk uygulamamdan burada bulabilirsiniz: UIImage önbelleği hakkında StackOverflow sorusu

Diğer bir not - InterfaceBuilder kapakların altında imageNamed'i kullanır. Bu problemle karşılaşırsanız aklınızda bulundurmanız gereken bir şey.


Tam olarak aynı davranışı gördüm ve dosyadan okumak onu doğrudan çözdü. Ayrıca, 11.456 x 3.226 piksel, 15MB gibi çok büyük bir görüntü yüklemeye çalıştığımda da oluyor. Teorim, sistemin ImageNamed önbellek işlemi sırasında belleğin kısmen tükenmesidir. Ve bu vaka için yerleşik bir işlem yok.
Dogweather
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.