2010-02-12 15 views
5

हाल ही में स्टैक ओवरफ़्लो पर किसी ने मुझसे कहा कि नीचे कोड लीक नहीं करता है, कि संपत्ति प्रतिधारण ही संभालता है:iPhone: यह एक रिसाव या है नहीं

self.locationManager = [[CLLocationManager alloc] init]; 
dealloc में

:

self.locationManager = nil; 

जहां ज फ़ाइल में:

@property (nonatomic, retain) CLLocationManager *locationManager; 

मैंने सोचा था कि एक स्पष्ट रिसाव था और माना जाता है कि इस रिसाव को ठीक करना चाहिए:

self.locationManager = [[[CLLocationManager alloc] init] autorelease]; 

हालांकि उन्होंने दावा किया कि काम नहीं करेगा, क्योंकि उनके शब्दों में: "आप एक वर्ग के स्वायत्त गुण नहीं हैं। एक संपत्ति की स्वत: जनरेट की एक्सेसर बनाए रखने के लिए स्वचालित रूप से बनाए रखने संभाल लूंगा "

और वह मुझे आश्चर्य है कि अगर वह गलत है या मैं समझ नहीं किया है सभी को एक स्मृति प्रबंधन बनाया परिभाषित

संपादित करें 1: कोड

है
self.myName=[NSSting stringWithFormat:@"%@ is correct.", @"TechZen"]; 

self.locationManager = [[[CLLocationManager alloc] init] autorelease]; 

स्मृति प्रबंधन के लिहाज से किसी भी प्रकार भिन्न है?

लड़का कहता है कि पहला व्यक्ति सही है और दूसरे को मना कर देता है। दूसरा दूसरा इतना गलत क्यों होगा? जहां तक ​​मैं दोनों गुणों को ऑटोरेलेज्ड उदाहरणों को आवंटित कर सकता हूं, लेकिन किसी भी तरह से एक जिद्दी तर्क है कि दूसरा गलत है। मैं इसे नहीं देख सकता, किसी भी मदद का स्वागत किया जाएगा।

+1

अपने संपादित करें 1 पर, बुद्धिमान बनाए रखने-गिनती, वे एक ही हैं। उन वस्तुओं को सिर्फ एक बार बनाए रखा जाता है। सभी सुविधा कार्यों में एक अंतर्निहित ऑटो-रिलीज है। यदि आपको init कथन में शब्द आवंटन नहीं दिखाई देता है, तो चर स्वचालित है। आप alloc का उपयोग करते हैं, तो आप –

उत्तर

7

गणना और रिलीज की गणना इस मामले में मदद करती है। यह निश्चित रूप से एक रिसाव है। आपकी locationManager ऑब्जेक्ट को 2 बार बनाए रखा जाएगा: एक बार alloc/init कॉल, और एक बार संपत्ति द्वारा। संपत्ति को nil पर सेट करना केवल एक बार locationManager जारी करेगा।

संपादन 1 में दिए गए उदाहरणों के लिए, वे वास्तव में वही हैं। ऐसा लगता है कि अन्य डेवलपर के पास तुरंत ऑटोरेलीज़िंग का असर होता है या यह समझ में नहीं आता कि autorelease क्या करता है।

0

नीचे इस लाइन को जोड़ें ... यह स्पष्ट रूप से स्थान प्रबंधक के लिए आपकी बनाए रखने की गिनती देता है। यह आपको बताएगा कि आपको इसे मैन्युअल रूप से रिलीज़ करने की आवश्यकता है या नहीं।

NSLog(@"retainCount:%d", [locationManager retainCount]); 

संपादित करें:

[locationManager release]; 
+0

autorelease का उपयोग करना चाहिए नहीं, नहीं, मैं धारणात्मक पूछ रहा हूँ। इसके अलावा, एनएसब्लॉगिंग बनाए रखने की गणना लीक का एक अच्छा उपाय नहीं है। –

+0

ओह ठीक है। खैर सबसे अच्छा अभ्यास आप dealloc में करना चाहिए, क्योंकि आपके वस्तु जब autorelease पूल बहा दिया जाता है जारी नहीं की जाएगी। ऊपर संपादित – Zinc

+0

NSObject क्लास संदर्भ से: "महत्वपूर्ण: यह विधि [retainCount] आमतौर पर स्मृति प्रबंधन समस्याओं को डीबग करने में कोई मान नहीं है [...] यह बहुत ही असंभव है कि आप इस विधि से उपयोगी जानकारी प्राप्त कर सकते हैं।" – jnic

1

@jnic: आप आश्चर्यजनक गलत हैं। जहां तक ​​मैं इसे समझता हूं, संपत्ति का पिछला मूल्य रिलीज संदेश भेजा जाता है, न कि उस वस्तु को जिसे आप संपत्ति को असाइन करना चाहते हैं। तो, हां प्रस्तावित कोड वास्तव में लीक करता है और आपको एक ऑटोरेलीज़ संदेश भेजना होगा जैसा कि आपने सोचा था, अहमम emrah

4

के शब्दों को बनाए रखने संपत्ति विकल्प हैं:

  • वर्ष मूल्य (यदि हो तो) एक रिलीज संदेश
  • नया मान संदेश

इसलिए बनाए रखने हो जाता हो जाता है, आपके CLLocationManager इंस्टेंस में सेटटर के बाद 2 की बरकरार होगी। एलोक और एक बनाए रखने वाले सेटर में से एक। वैकल्पिक रूप से

CLLocationMamnager *aLocationManager = [[CLLocationManager alloc] init]; 
self.locationManager = aLocationManager; 
[aLocationManager release]; 

, autorelease पूल में जोड़ने इतना है कि यह कम से कम अंत में free'd किया जाएगा: आप सही सेटर के बाद एक रिहाई संदेश भेजना चाहिए। जैसा आप अपने आप को लिखा था:

self.locationManager = [[[CLLocationManager alloc] init] autorelease]; 

और भी बेहतर, का उपयोग नहीं करते बनाए रखने संपत्ति विकल्प। इसे (डिफ़ॉल्ट) असाइन करें और आप तब भी जाने के लिए तैयार हैं जब आप एक बनाए गए ऑब्जेक्ट का उपयोग कर रहे हैं।

+0

उत्तर –

-2

ठीक है, यह सौदा है।

जब आप ऐसा तरह एक संपत्ति ...

@property (nonAtomic, retain) NSString myName; 

... क्योंकि संपत्ति की चूक की कमान परिभाषित इसकी वास्तव में के रूप में यह परिभाषित करने की तरह:

@property (nonAtomic, readwrite, retain, getter=getMyName,setter=setMyName) NSString myName; 

जब आप @synthesize myName; का उपयोग दृश्यों के पीछे, शिकायतकर्ता एक गेटटर विधि उत्पन्न करता है जो इस तरह कुछ दिखता है:

-(void) setMyName:(NSString *) aString{ 
    if (!(myString==aString) { //test if a string is the same **object** as the current myString 
     if (aString != nil) { // if nil we don't want to send a retain 
      [aString retain]; // increment the retain count by one 
     }   
     [myString release]; //decrement the retain count of the currently assigned string by one. 
     myString=nil; //set the pointer to nil to ensure we don't point to the old string object 
     myString=aString; //assign the newly retained object to the myString symbol  
    } 
} 

जैसा कि आप देख सकते हैं, किसी भी स्रोत से किसी भी स्ट्रिंग, किसी भी पूर्व रखरखाव गिनती, ऑटोरेलेस्ड या नहीं, स्वचालित रूप से असाइनमेंट पर विधि द्वारा बनाए रखा जाएगा और जब कोई नया मान असाइन किया जाएगा, तो यह विधि द्वारा स्वचालित रूप से जारी किया जाएगा। एकाधिक असाइनमेंट बनाए रखने की गिनती को ढेर नहीं करेंगे। जब तक आप जेनरेट किए गए सेटर का उपयोग करते हैं, तब तक निर्दिष्ट ऑब्जेक्ट (इस मामले में एस्ट्रिंग) में हमेशा एक गिनती होगी जो इसे कक्षा में जीवंत रखेगी।

यह वह जगह है आपने ऐसा क्यों कर सकते हैं ...

self.myName=[NSSting stringWithFormat:@"%@ is correct.", @"TechZen"];

यह करने के लिए बिना:

self.myName=[[NSSting stringWithFormat:@"%@ is correct.", @"TechZen"] retain]; 

... और नहीं चिंता करने की है, तो स्ट्रिंग मान अचानक गायब हो जाएगा जब autoreleasepool नालियों की है।

हालांकि अगर आप कभी भी फोन ...

[self.myName release]; 

... dealloc के बाहर कहीं भी, तो संपत्ति में वस्तु जब तक आप इसे लगातार ट्रैक nilled हो सकती है। उसी टोकन से, यदि आप कॉल करते हैं ..

[self.myName retain]; 

... कहीं भी, तो संपत्ति में वस्तु का रिसाव हो जाएगा (संभवतः के बाद भी स्वयं वस्तु पुनः आवंटित की जाती किया गया है।)

यही कारण है कि मैं कहता हूँ बनाए रखने या सौंपा किसी भी वस्तु autorelease करने के लिए कभी नहीं या एक संपत्ति में नकल की। यह केवल व्यर्थ नहीं बल्कि उत्पादक काउंटर है। यह इस प्रकार है कि आप केवल कॉल करने के लिए एक संपत्ति को रिलीज क्योंकि सेटर द्वारा बनाए रखने गिनती की कुशल ट्रैकिंग मतलब है कि आप संपत्ति शून्य तुम अब भी जरूरत हो सकती है, भले ही कर सकते हैं कि जब आप स्वयं वस्तु के साथ किया जाता है चाहता हूँ।

autorelease एक संपत्ति के लिए आवश्यक कभी नहीं रहा है, क्योंकि संपत्ति हमेशा स्वयं वस्तु और किसी भी अन्य वस्तु आंतरिक प्रतिधारण संभाल चाहिए, अगर यह आत्म वस्तु की संपत्ति का उपयोग करता है के द्वारा बनाए रखा है।

एक बार जब आप समझते हैं कि क्या उत्पन्न accessors अंदर पर चला जाता है, नियम स्पष्ट हैं। संपत्ति की वस्तु को स्पष्ट रूप से कभी न रखें। Dealloc में किसी संपत्ति की ऑब्जेक्ट को कभी भी न छोड़ें। किसी संपत्ति की ऑब्जेक्ट को स्वतः न करें।

इन नियमों के लिए स्पष्ट अनुशासन हमेशा स्वयं ऑब्जेक्ट में self.propertyName संदर्भों का उपयोग करना है ताकि यह सुनिश्चित किया जा सके कि संपत्ति का प्रतिधारण स्वचालित रूप से प्रबंधित हो। ,

self.locationManager = [[[CLLocationManager alloc] init]autorelease]; 

अब इस चर सिर्फ एक बार बनाए रखा गया है: इस प्रकार

self.locationManager = [[CLLocationManager alloc] init]; 

यह शायद सबसे अच्छा लिखा है:

+0

उत्तर के लिए बहुत कुछ धन्यवाद, self.myName = [NSSting stringWithFormat: @"% @ सही है। ", @" TechZen "]; बिल्कुल self.locationManager = [[[CLLocationManager alloc] init] autorelease]; मेमोरी प्रबंधन-वार मुझे विश्वास नहीं है कि आप इसे कैसे देख सकते हैं। –

2

निम्नलिखित बयान दो बार बनाए रखा है, और इस तरह के रूप में दो बार जारी किया जाना चाहिए , और आप इसे अपनी कक्षा के डेलोक फ़ंक्शन में रिलीज़ कर सकते हैं।

इसके अलावा, अगर आप निम्न कोड पंक्ति चलाने के लिए, एक रिलीज में कहा जाता है:

locationManager = nil; 

locationManager के बाद से संश्लेषित, जब आप इसे शून्य करने के लिए सेट है, यह पहले जारी किया जाता है।

इसके अलावा, अगर आप निम्नलिखित किया था, locationManager पहले जारी किया जाएगा, तो पर्दे के पीछे रीसेट:

self.locationManager = foo; 
अंत में

, एक EXC_BAD_ACCESS साथ क्रैश हो सकता है क्योंकि आप डबल locationManager छोड़ दें सेट कर रहे हैं निम्नलिखित यह foo के लिए:

self.locationManager = [[[CLLocationManager alloc] init]autorelease]; 
[locationManager release]; 
self.locationManager = foo; 
1

अंगूठे का सरल नियम: एक संपत्ति "बनाए रखने", हमेशा यह एक autoreleased चर देना (यदि आप इसे बना रहे हैं) जब तक कि बेशक आप भी इसे कहीं और बनाए रखने की आवश्यकता के रूप में चिह्नित किया जाता है।

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