2010-01-26 14 views
14

मेरे पास एक ऐसा फ़ंक्शन है जो कुछ बिटमैप डेटा लेता है और इससे UIImage * लौटाता है। ऐसा कुछ ऐसा दिखता है:बफर-> CGImageRef-> UIImage के लिए सही मेमोरी प्रबंधन पैटर्न क्या है?

UIImage * makeAnImage() 
{ 
    unsigned char * pixels = malloc(...); 
    // ... 
    CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, pixels, pixelBufferSize, NULL); 
    CGImageRef imageRef = CGImageCreate(..., provider, ...); 
    UIImage * image = [[UIImage alloc] initWithCGImage:imageRef]; 
    return [image autorelease]; 
} 

क्या कोई यह बता सकता है कि यहां कौन सी मेमोरी है? मैं ठीक से साफ करना चाहता हूं, लेकिन मुझे यकीन नहीं है कि इसे सुरक्षित तरीके से कैसे किया जाए। डॉक्स इन पर अस्पष्ट हैं। यदि UIImage बनाने के बाद इस फ़ंक्शन के अंत में free पिक्सेल, और फिर UIImage का उपयोग करें, तो मैं क्रैश करता हूं। यदि मैं UIImage बनाने के बाद प्रदाता या छवि रिफ को रिलीज़ करता हूं, तो मुझे कोई क्रैश दिखाई नहीं देता है, लेकिन वे स्पष्ट रूप से पिक्सल को सभी तरह से गुजर रहे हैं, इसलिए मैं इन मध्यवर्ती राज्यों को जारी करने के बारे में सोच रहा हूं।

(मुझे प्रति सीएफ डॉक्स पता है कि मुझे बाद में दोनों को रिलीज करने की आवश्यकता होनी चाहिए क्योंकि वे फ़ंक्शन बनाने से आते हैं, लेकिन क्या मैं यूआईएममेज का उपयोग करने से पहले ऐसा कर सकता हूं?) संभवतः मैं प्रदाता के डेलोक कॉलबैक का उपयोग कर सकता हूं पिक्सल बफर साफ़ करें, लेकिन और क्या?

धन्यवाद!

उत्तर

21

अंगूठे का नियम यहां है "-release * यदि आपको इसकी आवश्यकता नहीं है"।

क्योंकि आप नहीं रह गया है provider और imageRef बाद में की जरूरत है, तो आप चाहिए -release उन सभी को, यानी

UIImage * image = [[UIImage alloc] initWithCGImage:imageRef]; 
CGDataProviderRelease(provider); 
CGImageRelease(imageRef); 
return [image autorelease]; 

pixel, रेफरी की गिनती द्वारा प्रबंधित नहीं है तो आप के लिए उन्हें मुक्त करने के लिए तटरक्षक एपीआई बताने की आवश्यकता जब आवश्यक हो। यह करें:

void releasePixels(void *info, const void *data, size_t size) { 
    free((void*)data); 
} 
.... 

CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, pixels, pixelBufferSize, releasePixels); 

वैसे, आप +imageWithCGImage: बजाय [[[* alloc] initWithCGImage:] autorelease] उपयोग कर सकते हैं। इससे भी बेहतर, +imageWithData: है इसलिए आपको सीजी और malloc सामान से गड़बड़ करने की आवश्यकता नहीं है।

(*:। माना जाता है कि शुरू से ही शून्य retainCount पहले से ही है जब छोड़कर)

+0

धन्यवाद केनी। यह एक अच्छी तरह से संक्षेप में वर्णन है; मुझे लगता है कि कच्चे ढेर बफर की अप्रत्याशितता से मुझे थोड़ा फेंक दिया गया था, लेकिन हमेशा के रूप में, नियमों पर भरोसा करें और आपको पुरस्कृत किया जाएगा। चीयर्स। –

+1

बस कुछ स्पष्टीकरण जोड़ने के लिए, कोर फ़ंक्शंस में मुख्य शब्द "बनाएं" और "नया" हैं। यदि फ़ंक्शन में इनमें से कोई भी शब्द है, तो आपको लौटाई गई स्मृति को रिलीज़ करना होगा। अधिकांश कोर डेटा प्रकार CFType संगत हैं। जिसका अर्थ यह है कि यदि आप इसे आसान बनाते हैं तो आप उद्देश्य-सी बनाए रखने/रिलीज/ऑटोरेलीज़ कॉल का उपयोग कर सकते हैं। यानी [(आईडी) imageRef रिलीज]; या CFRelease (imageRef); –

+0

यदि आप 'CFRelease' का उपयोग करते हैं तो' imageRef' 'NULL' जांचना याद रखें। – kennytm

-2

ऐ, यह कोड मुझे queasy बनाता है। एक पुराने नियम के अनुसार, मैं एक ही समारोह/विधि/चयनकर्ता में सी और सी ++, और सी/उद्देश्य-सी मिश्रण और मिलान करने की कोशिश नहीं करता हूं।

इसे दो तरीकों से तोड़ने के बारे में कैसे। इस मेकएएनमेज को एएनआईमेज रिफ बनाने में बदलाव करें और यूआईएममेज सृजन को दूसरे ओब्जे-सी चयनकर्ता में खींचें।

+0

हालांकि मैं प्रतिक्रिया को समझने :) तो अब भी कर रही है नहीं है मेरी मेमोरी प्रबंधन समस्या में मदद करें। मुझे अभी भी समस्या है कि पाइपलाइन की शुरुआत में कच्चे बाइटों को पार करने से मुझे यूआईएममेज के साथ छोड़ दिया जाता है कि किसी भी तरह से अभी भी उन बाइटों की आवश्यकता होती है। तो यह कोड ऐसा लगता है उससे कहीं अधिक संबंधित है। –

8
unsigned char * pixels = malloc(...); 

आप pixels बफर के मालिक हैं, क्योंकि आप इसे mallocked।

CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, pixels, pixelBufferSize, NULL); 

कोर ग्राफिक्स कोर फाउंडेशन नियमों का पालन करती। आप डेटा प्रदाता के स्वामी हैं क्योंकि आप Created इसे करते हैं।

आपने रिलीज कॉलबैक प्रदान नहीं किया है, इसलिए आपके पास अभी भी pixels बफर है। अगर आपने रिलीज कॉलबैक प्रदान किया था, तो CGDataProvider ऑब्जेक्ट यहां बफर का स्वामित्व लेगा। (आम तौर पर एक अच्छा विचार है।)

CGImageRef imageRef = CGImageCreate(..., provider, ...); 

आप CGImage वस्तु के मालिक हैं, क्योंकि आप इसे बनाया गया।

UIImage * image = [[UIImage alloc] initWithCGImage:imageRef]; 

आपके पास UIImage ऑब्जेक्ट है क्योंकि आपने इसे आवंटित किया है।

आप अभी भी CGImage ऑब्जेक्ट का स्वामी हैं। यदि UIImage ऑब्जेक्ट CGImage ऑब्जेक्ट का मालिक बनना चाहता है, तो यह या तो इसे बनाए रखेगा या अपनी प्रतिलिपि बनायेगा।

return [image autorelease]; 

आप छवि का अपना स्वामित्व छोड़ देते हैं।

तो आपका कोड पिक्सल को लीक करता है (आपने डेटा प्रदाता को स्वामित्व स्थानांतरित नहीं किया है और आपने उन्हें स्वयं जारी नहीं किया है), डेटा प्रदाता (आपने इसे जारी नहीं किया है), और CGImage (आपने नहीं किया ' इसे जारी नहीं)। एक निश्चित संस्करण डेटा प्रदाता को पिक्सल के स्वामित्व को स्थानांतरित करेगा, और यूआईएममेज तैयार होने तक डेटा प्रदाता और CGImage दोनों को रिलीज़ करेगा। या, केवल imageWithData: का उपयोग करें, जैसा कि केनीटीएम ने सुझाव दिया था।

+0

पीटर: इस माध्यम से चलने के लिए समय निकालने के लिए धन्यवाद, खासकर क्यू एंड ए पार्टी समाप्त होने के बाद। –

1
unsigned char * pixels = malloc(...); 

मैं भी CGImageCreate का उपयोग कर रहा अंत में अच्छा और सरल समाधान पाया के बाद malloc/मुक्त के साथ समस्या थी। मैं बस की जगह लाइन:

CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, pixels, pixelBufferSize, NULL); 

साथ: मैं mallocked स्मृति मुक्त कर सकता है

NSData *data = [NSData dataWithBytes:pixels length:pixelBufferSize]; 
CGDataProviderRef provider = CGDataProviderCreateWithCFData((CFDataRef)data); 

बस उस के बाद:

free (pixels); 
+1

इसके लिए सभी बाइट्स की प्रतिलिपि बनाना आवश्यक है, जो कुछ उपयोग मामलों के लिए अक्षम हो सकता है। इसके बजाय, [NSData डेटा WithBytesNoCopy: लंबाई] का उपयोग करें जो बाइट्स का स्वामित्व ले लेगा, और जब उन्हें अब आवश्यकता नहीं है तो उन्हें आपके लिए मुक्त कर दें। –

संबंधित मुद्दे