के बाद मेरी कोड है लाइन टाइमर को अमान्य कर रहा है। अगली दो पंक्तियों को भी बुलाया नहीं जाता है। मुझे एक "EXC_BAD_ACCESS" त्रुटि मिलती है। क्या कोई मुझे बता सकता है कि ऐसा क्यों हो रहा है, और कक्षा में एनएसटीमर सदस्य चर को रोकने और जारी करने का उचित तरीका क्या है।समस्या dealloc में NSTimer अमान्य
उत्तर
मैंने कुछ शोध और परीक्षण किए, और मेरे अपने प्रश्न का उत्तर समझ सकते थे। ठीक है, यह यहां जाता है:
जब भी हम कोपर लक्षित करते हैं, तो टाइमर हमारे ऑब्जेक्ट का संदर्भ रखता है। यदि टाइमर दोहराया जा रहा है (या लंबी अवधि की अवधि है), तो यह स्वयं पर अमान्य नहीं होगा (या दोहराए जाने पर स्वचालित रूप से अमान्य करने में बहुत लंबा समय लगेगा)। इसलिए, इस दौरान ऑब्जेक्ट को रिलीज़ होने के बावजूद, यह dealloc
विधि को कॉल नहीं करेगा, क्योंकि बनाए रखने की गिनती कम से कम 1 होगी। अब, मैं जबरन जारी रखने तक अपने ऑब्जेक्ट को दोबारा रिलीज़ करने की कोशिश कर रहा था गिनती 0 हो गई। यह मेरी गलती थी।
लेकिन यदि आप ऐसा नहीं करते हैं, तो आपका ऑब्जेक्ट ज़िंदा रहेगा, और अंत में आप स्मृति रिलीज करेंगे क्योंकि आप विभिन्न रिलीज द्वारा उस ऑब्जेक्ट के बाकी संदर्भ खो देते हैं। केवल एक ही रखा गया NSTimer
के साथ होगा। यह एक डेडलॉक स्थिति की तरह लगता है। मेरा कोड क्रैश हो गया, क्योंकि जब delloc
ने NSTimer
को अमान्य करने का प्रयास किया, तो उसने उस संदर्भ को रिलीज़ करने का प्रयास किया जो यह हो रहा था। लेकिन चूंकि मैं एक स्मार्टस रहा था और पहले से ही 0 को बरकरार रखता हूं, इससे स्मृति अपवाद होता है।
इसे हल करने के लिए, सबसे पहले मैंने अपना कार्य साफ़ कर दिया और ऑब्जेक्ट को जबरन डेलोकेट करने के लिए कोड हटा दिया।फिर इससे पहले कि मैं ऑब्जेक्ट को डेलोकेट करना चाहता था, मैंने एनएसटीमर के अमान्य फ़ंक्शन को बुलाया। इसने लक्ष्य के उदाहरण को जारी किया कि टाइमर था। इसके बाद, मेरी ऑब्जेक्ट पर release
को कॉल करने से सफलतापूर्वक इसे डेलोकेट किया गया।
नीचे की रेखा है, यदि आपके ऑब्जेक्ट में एनएसटीमीटर हैं जो स्वचालित रूप से दोहराने या अमान्य नहीं होते हैं, तो उन्हें कभी भी डेलोक फ़ंक्शन में अमान्य नहीं करें। जब तक टाइमर आपके ऑब्जेक्ट पर उदाहरण धारण नहीं कर लेता तब तक डेलोक को कॉल नहीं किया जाएगा। ऑब्जेक्ट को रिलीज़ करने से पहले टाइमर को अमान्य करने के लिए क्लीनअप फ़ंक्शन करें। यही वह समाधान है जिसके साथ मैं आया था। यदि वहाँ एक बेहतर व्यक्ति है, तो मैं निश्चित रूप से जानना चाहता हूं।
कुछ चीजें हैं जिन्हें आपको साफ करने के लिए संबोधित करना चाहिए।
आपकी कक्षा घोषणा थोड़ी दूर है। आप NSObject से प्राप्त करना चाहते हैं, तो सही सिंटैक्स है:
@interface GObject : NSObject
अपने कार्यान्वयन में, आप - (id)init
बजाय - (void)Initialize
लागू करना चाहिए। कोई उदाहरण विधि - (void)Initialize
नहीं है ... एक स्थिर विधि + (void)initialize
है। +
और पूंजीकरण में अंतर, जो महत्वपूर्ण है): वर्ग को अपनी पहली विधि प्राप्त करने से पहले initialize
विधि को आपके प्रोग्राम में एक बार बुलाया जाता है।
इस मामले में, आपकी Initialize
विधि बिल्कुल नहीं कहा जा रहा है (यह गलत वर्तनी है, और यह एक स्थिर विधि के बजाय एक उदाहरण विधि है)।
- (id)init {
if (self = [super init]) {
self.m_Timer = [NSTimer scheduledTimerWithTimeInterval:5.0
target:self
selector: @selector(TimerCallback:)
userInfo: nil
repeats: YES];
}
return self;
}
अन्त में, संपत्ति बयान से पहले @
प्रतीक का उपयोग सुनिश्चित करें:
@property(nonatomic, retain) NSTimer* m_Timer;
और भूल नहीं है इसके बजाय, आप init
, जो NSObject उदाहरणों के लिए नामित प्रारंभकर्ता है लागू करना चाहते हैं इसे अपने कार्यान्वयन में संश्लेषित करने के लिए:
@implementation GObject
@synthesize m_Timer;
हां, यही कारण है कि दुर्घटना हो रही है। टाइमर को कभी भी प्रारंभ नहीं किया गया है क्योंकि 'प्रारंभ करें' विधि कभी नहीं कहा जाता है, और इस प्रकार, टाइमर कभी नहीं बनाता है। फिर आपके डेलोक विधि को पॉइंटर पर रिलीज़ करने की तुलना में कभी भी प्रारंभ नहीं किया गया था, यह सूचक प्रोग्राम में किसी भी यादृच्छिक वस्तु, या यहां तक कि कचरा भी इंगित कर सकता है। – Jasarien
मुझे खेद है, मुझे यह उल्लेख करना चाहिए था कि मैं इस कोड को मेरी याददाश्त से लिख रहा था क्योंकि मैं वर्तमान में अपने मैक के पास नहीं हूं। मेरे वास्तविक कोड में मैंने यह सब किया, -इनिट भाग को छोड़कर। – Prashant
मैंने आपकी सलाह के अनुसार उपरोक्त कोड को सही किया है। प्रारंभिक विधि के लिए, चूंकि मैंने इसे बनाया है, जब भी मैं अपनी ऑब्जेक्ट को तुरंत चालू कर रहा हूं, तो मैं इसे कॉल कर सकता हूं, जैसे कि गोब्जेक्ट * ए = [गोब्जेक्ट एलोक]; [एक प्रारंभिक]; मैं समझता हूं कि यह एक सर्वोत्तम अभ्यास नहीं है, लेकिन मुझे यकीन है कि इसकी अनुमति है। कृपया सलाह दीजिये कि आरंभिक विधि को बुलाया जाता है और टाइमर निकाल दिया जाता है। इसलिए, यह समस्या नहीं है। मेरी पोस्ट को सही करने में मेरी मदद करने के लिए धन्यवाद। – Prashant
मेरे पास दृश्य नियंत्रक में दोहराए गए एनएसटीमर का उपयोग करके एक ही स्मृति रिसाव समस्या है। यह दृश्य नियंत्रक तब जारी नहीं होगा जब इसे करना चाहिए। अंततः मैंने अपने टाइमर को मुख्य एप्लिकेशन प्रतिनिधि कोड पर ले जाकर इस मुद्दे को हल किया जहां टाइमर को रिलीज़ करने की कोई आवश्यकता नहीं है।
अच्छी तरह से, मुझे यह कहना है कि आप ऐप्पल के क्लास संदर्भ जैसे सेब डेवलपर के दस्तावेज़ों का उल्लेख कर सकते हैं। आप वहां से देख सकते हैं कि जब अमान्य: विधि कहा जाता है, टाइमर की रिलीज: विधि को अमान्य करने से पहले बुलाया जाएगा: विधि रिटर्न।
एक और समाधान एक अलग ऑब्जेक्ट बनाना होगा जो NSTimer
कॉलबैक (कुछ TimerController
) से संबंधित है। यदि आवश्यक हो, तो वह ऑब्जेक्ट आपके self
नियंत्रक पर विधियों को कॉल कर सकता है।
अब टाइमर self
के लिए एक संदर्भ नहीं रह जाएगी और जब self
पुनः आवंटित की जाती हो जाता है, - dealloc
बुलाया जाना चाहिए और आप को अमान्य कर सकते हैं और TimerController
और टाइमर ही नहीं के बराबर करने के लिए निर्धारित किया है।
क्या आप @ सिंथेसाइज के साथ संपत्ति का गेटर/सेटर बना रहे हैं? – gerry3
हां, मुझे अपनी कक्षा के बाहर से इस टाइमर तक पहुंचने की ज़रूरत है। हालांकि सेटटर की आवश्यकता नहीं है। – Prashant