2009-05-29 13 views
116

फरवरी 2014 को संपादित करें: ध्यान दें कि यह प्रश्न आईओएस 2.0 से है! तब से छवि आवश्यकताएं और हैंडलिंग बहुत अधिक हो गई है। रेटिना छवियों को बड़ा बनाता है और उन्हें थोड़ा और जटिल बना देता है। आईपैड और रेटिना छवियों के लिए निर्मित समर्थन के साथ, आपको निश्चित रूप से अपने कोड में ImageNamed का उपयोग करना चाहिए।UIImage छवि को डिस्पेल करना नामांकित: FUD

मुझे बहुत से लोग कहते हैं कि imageNamed खराब है लेकिन प्रदर्शन करने वाले लोगों की संख्या बराबर है - खासकर जब UITableView एस प्रस्तुत करते हैं। iPhoneDeveloperTips.com

UIImage के imageNamed तो लीक करने के लिए प्रयोग विधि यह बचना ही सही था लेकिन हाल के रिलीज में तय किया गया है पर या उदाहरण के लिए this SO questionthis article देखें। मैं कैशिंग एल्गोरिदम को बेहतर तरीके से समझना चाहता हूं कि इस बारे में एक तर्कसंगत निर्णय लेने के लिए कि मैं अपनी छवियों को कैश करने के लिए सिस्टम पर भरोसा कर सकता हूं और जहां मुझे अतिरिक्त मील जाने और इसे स्वयं करने की आवश्यकता है। मेरी वर्तमान मूलभूत समझ यह है कि यह फ़ाइल नाम से संदर्भित UIImages का एक साधारण NSMutableDictionary है। यह बड़ा हो जाता है और जब स्मृति समाप्त हो जाती है तो यह बहुत छोटा हो जाता है।

उदाहरण के लिए, क्या कोई यह सुनिश्चित करने के लिए जानता है कि imageNamed के पीछे छवि कैश didReceiveMemoryWarning का जवाब नहीं दे रहा है? ऐसा लगता है कि ऐप्पल ऐसा नहीं करेगा।

यदि आपके पास कैशिंग एल्गोरिदम में कोई अंतर्दृष्टि है, तो कृपया इसे यहां पोस्ट करें।

+1

मैं रहस्य में हूं। :) – Kriem

+2

मुझे भी। ऐसा लगता है कि एसओ जीनियस से इतना भरा नहीं है जैसा मैंने सोचा था। –

+0

ऐसा लगता है कि आपने कुछ समय की जांच की है। क्या आपने कोई प्रयोग किया है जो नवीनतम कोको-टच संस्करण के साथ नामित यूआईएममेज छवि का कोई नकारात्मक प्रभाव दिखाएगा? एक UITableView बनाएं और बहुत सारी (कई हजारों) पंक्तियां जोड़ें और देखें कि जब आप प्रत्येक पंक्ति में अलग-अलग छवि दिखाते हैं तो प्रदर्शन नीचे चला जाता है या नहीं। शायद तब लोग आपके निष्कर्षों पर टिप्पणी कर सकते हैं। – stefanB

उत्तर

86

tldr: ImagedNamed ठीक है। यह स्मृति अच्छी तरह से संभालती है। इसका इस्तेमाल करें और चिंता करना बंद करो।

नवंबर 2012 संपादित करें: ध्यान दें कि यह प्रश्न आईओएस 2.0 से है! तब से छवि आवश्यकताओं और हैंडलिंग बहुत से चले गए हैं। रेटिना छवियों को बड़ा बनाता है और उन्हें थोड़ा और जटिल बना देता है। आईपैड और रेटिना छवियों के लिए निर्मित समर्थन के साथ, आपको निश्चित रूप से अपने कोड में ImageNamed का उपयोग करना चाहिए। अब, वंशावली के लिए:

एप्पल देव मंचों पर sister thread कुछ बेहतर ट्रैफिक प्राप्त हुआ। विशेष रूप से Rincewind ने कुछ अधिकार जोड़ा।

आईफोन ओएस 2.x में समस्याएं हैं जहां छवि नामित: स्मृति चेतावनी के बाद भी कैश साफ़ नहीं किया जाएगा। उसी समय + छवि नामित: कैश के लिए बहुत अधिक उपयोग नहीं हुआ है, लेकिन सुविधा के लिए, जिसने संभवतया समस्या को बड़ा कर दिया है उससे कहीं अधिक होना चाहिए था।

चेतावनी

गति के मोर्चे पर, वहाँ क्या चल रहा है की एक सामान्य गलतफहमी है कि जब। सबसे बड़ी बात यह है कि + imageNamed: स्रोत फ़ाइल से छवि डेटा को डीकोड करता है, जो लगभग हमेशा डेटा आकार को बढ़ाता है (उदाहरण के लिए, एक स्क्रीन आकार की पीएनजी फ़ाइल संपीड़ित होने पर कुछ दर्जन केबी का उपभोग कर सकती है, लेकिन आधे एमबी से अधिक उपभोग करती है डिकंप्रेस्ड - चौड़ाई * ऊंचाई * 4)। इसके विपरीत + imageWithContentsOfFile: छवि डेटा की आवश्यकता होने पर हर बार उस छवि को डिक्रॉप कर देगा। जैसा कि आप कल्पना कर सकते हैं, अगर आपको केवल एक बार छवि डेटा की आवश्यकता है, तो आपने यहां कुछ भी नहीं जीता है, इसके अलावा छवि के कैश किए गए संस्करण को चारों ओर लटकने के अलावा, और इसकी आवश्यकता होने की संभावना अधिक है। हालांकि, अगर आपके पास एक बड़ी छवि है जिसे आपको अक्सर फिर से निकालना है, तो विकल्प हैं, हालांकि मैं मुख्य रूप से अनुशंसा करता हूं कि वह बड़ी छवि को फिर से निकालने से बचें :)।

कैश के सामान्य व्यवहार के संबंध में, यह फ़ाइल नाम पर आधारित कैश करता है (इसलिए + छवि नाम के दो उदाहरण: उसी नाम के साथ उसी कैश किए गए डेटा के संदर्भ में होना चाहिए) और कैश गतिशील रूप से बढ़ेगा + छवि नाम के माध्यम से अधिक छवियों का अनुरोध करें:। आईफोन ओएस 2.x पर एक बग एक स्मृति चेतावनी प्राप्त होने पर कैश को संकुचित होने से रोकता है। कैश iPhone OS 3.0 पर स्मृति चेतावनी का सम्मान करना चाहिए:

और

मेरे समझ है कि + imageNamed है। जब आपको मौका मिलता है और बग की रिपोर्ट करते हैं तो इसका परीक्षण करें यदि आपको लगता है कि यह मामला नहीं है।

तो, आपके पास यह है। imageNamed: आपकी खिड़कियों को तोड़ नहीं देगा या आपके बच्चों की हत्या नहीं करेगा। यह बहुत आसान है लेकिन यह एक अनुकूलन उपकरण है। दुर्भाग्य से वह बुरी तरह से नामित किया गया है और वहाँ कोई equivaluent उपयोग करने के लिए के रूप में आसान है - इसलिए लोगों को यह अति प्रयोग और जब यह बस

मैं 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]]; 
} 

रेंसविंड ने अपना खुद का अनुकूलित संस्करण बनाने के लिए कुछ उदाहरण कोड भी शामिल किया। मैं नहीं देख सकता कि यह रखरखाव के लायक है लेकिन यहां यह पूर्णता के लिए है।

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

इस कोड के साथ व्यापार बंद यह है कि डीकोडेड छवि अधिक स्मृति का उपयोग करती है लेकिन प्रतिपादन तेज़ है।

+0

ऐसा लगता है कि आईओएस 11 पर, [UIImage imageNamed:] छवियों को कैश से छवियों को बेदखल नहीं कर रहा है अगर छवियां xcasset कैटलॉग से आ रही हैं। यह स्मृति से बाहर दुर्घटनाओं की ओर जाता है। –

5

मेरे अनुभव में, छवि नाम द्वारा बनाई गई छवि कैश स्मृति चेतावनियों का जवाब नहीं देती है। मेरे पास दो अनुप्रयोग थे जो दुबला थे क्योंकि मैं उन्हें एमएम प्रबंधन तक प्राप्त कर सकता था, लेकिन यादों की कमी के कारण अभी भी दुर्घटनाग्रस्त हो रहा था। जब मैंने छवियों को लोड करने के लिए नामित छवि का उपयोग करना बंद कर दिया, तो दोनों अनुप्रयोग नाटकीय रूप से अधिक स्थिर हो गए।

मैं स्वीकार करूंगा कि दोनों अनुप्रयोगों ने कुछ बड़ी छवियों को लोड किया है, लेकिन ऐसा कुछ भी नहीं जो सामान्य से पूरी तरह से बाहर हो। पहले आवेदन में, मैंने बस कैशिंग को पूरी तरह से छोड़ दिया क्योंकि यह संभावना नहीं थी कि उपयोगकर्ता दो बार एक ही छवि पर वापस आ जाएगा। दूसरे में, मैंने आपके द्वारा वर्णित एक बहुत ही सरल कैशिंग क्लास बनाया - यूआईएममेज को एनएसएमयूटेबल डिक्शनरी में रखते हुए और फिर मुझे मेमोरी चेतावनी मिलने पर इसकी सामग्री को फ्लश करना पड़ा। अगर छवि नामित: उस तरह कैश करना था, तो मुझे कोई प्रदर्शन अपग्रेड नहीं देखा जाना चाहिए था। यह सब 2.2 पर चल रहा था - मुझे नहीं पता कि इस पर कोई 3.0 प्रभाव है या नहीं।

आप यहाँ मेरी पहली app से इस समस्या के समाधान मेरे दूसरे प्रश्न पा सकते हैं: StackOverflow question about UIImage cacheing

एक अन्य टिप्पणी - InterfaceBuilder कवर के तहत imageNamed उपयोग करता है। यदि आप इस समस्या में भाग लेते हैं तो कुछ ध्यान में रखना चाहिए।

+0

मैंने सटीक वही व्यवहार देखा, और फ़ाइल से पढ़ने से इसे सीधे हल किया गया। साथ ही, ऐसा होता है जब मैं एक बहुत बड़ी छवि लोड करने का प्रयास करता हूं - 11,456 x 3,226 पीएक्स, 15 एमबी। मेरा सिद्धांत यह है कि सिस्टम ImageNamed कैश ऑपरेशन के माध्यम से स्मृति भाग-मार्ग से बाहर चला जाता है। और इस मामले के लिए कोई हैंडलिंग नहीं है। – Dogweather