नोट: यह गैर एआरसी स्मृति प्रबंधन के लिए विशेष रूप से लागू होता है।
चूंकि इसमें बहुत सारे विचार हैं और चेक किए गए उत्तर उचित रूप से बताते हैं कि "कोड उद्देश्य-सी में स्मृति प्रबंधन कैसे काम करता है, इस बारे में ज्ञान की गंभीर कमी दिखाता है," फिर भी किसी ने विशिष्ट त्रुटियों को इंगित नहीं किया है, मुझे लगता है मैं एक जवाब जोड़ूंगा जो उन पर छूएगा।
आधारभूत स्तर के नियम हम बुला तरीकों के बारे में याद करने के लिए है:
विधि कॉल शब्द alloc, नई, कॉपी, या बनाए रखने शामिल है, तो हम बनाई गई वस्तु का स्वामित्व है। ¹ अगर हमारे पास किसी ऑब्जेक्ट का स्वामित्व है, तो इसे जारी करने की हमारी ज़िम्मेदारी है।
यदि विधि कॉल में कोई शब्द नहीं है, तो हमारे पास बनाए गए ऑब्जेक्ट का स्वामित्व नहीं है। ¹ यदि हम पर किसी ऑब्जेक्ट का स्वामित्व नहीं है, तो इसे हमारी ज़िम्मेदारी जारी नहीं है, और इसलिए हमें इसे कभी नहीं करना चाहिए।
की प्रत्येक पंक्ति में ओपी के कोड देखें:
-(UIImage *) downloadImageToFile {
हम एक नई विधि शुरू कर दिया। ऐसा करने में हमने एक नया संदर्भ शुरू कर दिया है जिसमें प्रत्येक निर्मित वस्तुएं रहती हैं। इसे थोड़ा सा ध्यान में रखें।अगली पंक्ति:
NSURL * url = [[NSURL alloc] initWithString: self.urlField.text];
हम url
ही: शब्द alloc वहाँ हमें बताता है कि हम वस्तु का स्वामित्व है, और हम इसे अपने आप को रिलीज करने के लिए की आवश्यकता होगी कि। अगर हम नहीं करते हैं तो कोड स्मृति को रिसाव करेगा।
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
हम ही नहीं paths
: चार जादुई शब्द का कोई उपयोग नहीं है, तो हम स्वामित्व की जरूरत नहीं है और यह अपने आप को कभी नहीं जारी करना होगा। कोई जादुई शब्द = कोई स्वामित्व:
NSString *documentsDirectory = [paths objectAtIndex:0];
हम documentsDirectory
स्वामी नहीं हैं।
[paths release]
वापस लाइनों के एक जोड़े हम देखते हैं कि हम रास्तों के स्वामी नहीं हैं जा रहे हैं, तो यह रिलीज एक EXC_BAD_ACCESS दुर्घटना का कारण के रूप में हम कुछ अब मौजूद नहीं है का उपयोग करने की कोशिश करेंगे। कोई जादुई शब्द = कोई स्वामित्व:
NSString * path = [documentsDirectory stringByAppendingString:@"/testimg.png"];
हम path
स्वामी नहीं हैं। alloc शब्द उपयोग है कि हम वस्तु का स्वामित्व है, वहाँ बताता है और हम इसे अपने आप को रिलीज करने के लिए की आवश्यकता होगी कि:
NSData * data = [[NSData alloc] initWithContentsOfURL:url];
हम data
के मालिक हैं। अगर हम नहीं करते हैं तो कोड स्मृति को रिसाव करेगा।
निम्नलिखित दो पंक्तियां कुछ भी नहीं बनाती हैं या रिलीज़ नहीं करती हैं। फिर अंतिम पंक्ति आती है:
}
विधि खत्म हो गई है, इसलिए चर के लिए संदर्भ समाप्त हो गया है। कोड को देखते हुए हम देख सकते हैं कि हमारे पास url
और data
दोनों का स्वामित्व है, लेकिन उनमें से कोई भी रिलीज़ नहीं हुआ। नतीजतन जब भी इस विधि को बुलाया जाता है तो हमारा कोड स्मृति को रिसाव करेगा।
NSURL
ऑब्जेक्ट url
बहुत बड़ा नहीं है, इसलिए यह संभव है कि हम कभी भी रिसाव को नोटिस न करें, हालांकि इसे अभी भी साफ किया जाना चाहिए, इसे रिसाव करने का कोई कारण नहीं है।
NSData
ऑब्जेक्ट data
एक पीएनजी छवि है, और यह बहुत बड़ा हो सकता है; जब भी इस विधि को बुलाया जाता है हम वस्तु के पूरे आकार को लीक कर रहे हैं। कल्पना करें कि हर बार एक टेबल सेल खींचा जाने पर इसे बुलाया जाता था: पूरे ऐप को तोड़ने में काफी समय नहीं लगेगा।
तो समस्याओं को ठीक करने के लिए हमें क्या करने की आवश्यकता है? , सही से पहले
-(UIImage *) downloadImageToFile {
// We own this object due to the alloc
NSURL * url = [[NSURL alloc] initWithString: self.urlField.text];
// We don't own this object
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
// We don't own this object
NSString *documentsDirectory = [paths objectAtIndex:0];
//[paths release] -- commented out, we don't own paths so can't release it
// We don't own this object
NSString * path = [documentsDirectory stringByAppendingString:@"/testimg.png"];
// We own this object due to the alloc
NSData * data = [[NSData alloc] initWithContentsOfURL:url];
[url release]; //We're done with the url object so we can release it
[data writeToFile:path atomically:YES];
[data release]; //We're done with the data object so we can release it
return [[UIImage alloc] initWithContentsOfFile:path];
//We've released everything we owned so it's safe to leave the context
}
कुछ लोगों को एक ही बार में सब कुछ जारी करने के लिए पसंद करते हैं: यह बहुत सरल, हम बस वस्तुओं को रिहा करने की जरूरत है, जैसे ही हम उनकी आवश्यकता नहीं आमतौर पर सही पिछली बार के बाद वे इस्तेमाल कर रहे है संदर्भ विधि के अंत में बंद हो जाता है। उस स्थिति में [url release];
और [data release];
दोनों }
ब्रेस बंद होने से ठीक पहले दिखाई देंगे। मुझे लगता है कि अगर मैं उन्हें कोड को साफ़ कर सकता हूं, तो कोड साफ़ हो जाता है, जब मैं इसे बाद में जाता हूं तो यह स्पष्ट करता है कि मैं ऑब्जेक्ट्स के साथ कहां से कर रहा हूं।
संक्षेप में प्रस्तुत करना: हम ही विधि में alloc
, new
, copy
, या retain
के साथ बनाई गई वस्तुओं कॉल इसलिए उन्हें रिलीज से पहले संदर्भ समाप्त होता है। हमारे पास कुछ और नहीं है और उन्हें कभी भी मुक्त नहीं करना चाहिए।
¹ वास्तव में चार शब्दों में जादुई कुछ भी नहीं है, वे सिर्फ एप्पल पर लोग सवाल में तरीकों बनाया द्वारा लगातार इस्तेमाल किया अनुस्मारक रहे हैं। यदि हम अपनी खुद की शुरुआत के लिए अपनी खुद की प्रारंभिकरण या प्रतिलिपि बनाने के तरीके बनाते हैं तो शब्दों को आवंटित करने, नए, प्रतिलिपि बनाने, या उचित तरीके से बनाए रखने की हमारी ज़िम्मेदारी है, और यदि हम उन्हें हमारे नामों में उपयोग नहीं करते हैं तो हम खुद को याद रखना होगा कि स्वामित्व पारित हो गया है या नहीं।
लिंक के लिए धन्यवाद। मेरे वास्तविक कोड में मैं पथ जारी करने की कोशिश कर रहा था जब मैं इसे स्पष्ट रूप से आवंटित नहीं कर रहा था, जिसके कारण बाद में समस्याएं उत्पन्न हुईं। और आप सही हैं, मैं बस ओबीजे-सी से शुरू कर रहा हूं और यह निश्चित रूप से अधिक जटिल है जितना मैंने सोचा था कि यह होगा। – Kevlar
कोई समस्या नहीं, उम्मीद है कि मैं बहुत कठोर नहीं था। वह दस्तावेज पढ़ने के लायक है। आपके विकास के साथ कामयाबी की शुभकामना! – August
मुझे हाल ही में EXC_BAD_ACCESS के बारे में बहुत सारे प्रश्न मिल रहे हैं इसलिए मैंने इसे http://loufranco.com/blog/files/Understanding-EXC_BAD_ACCESS.html लिखा है, इसे डिबगिंग तकनीकों की एक सूची के साथ। इस मामले में (बहुत से रिलीज), बिल्ड और विश्लेषण/स्कैन-बिल्ड शायद इसे ध्वजांकित कर दिया होगा। यदि नहीं, तो लाश को निश्चित रूप से सक्षम करना होगा। –