ऑब्जेक्टिव-सी डेलीगेट्स को आमतौर पर प्रॉपर्टी असाइन करने के बजाय रिटेन क्यों दिया जाता है?


176

मैं स्कॉट स्टीवेन्सन द्वारा बनाए गए अद्भुत ब्लॉग के माध्यम से सर्फिंग कर रहा हूं, और मैं 'असाइन' प्रॉपर्टी बनाम 'रिटेन' प्रतिनिधियों को सौंपने के एक मूल उद्देश्य-सी अवधारणा को समझने की कोशिश कर रहा हूं। ध्यान दें, दोनों एक कचरा एकत्र किए गए वातावरण में समान हैं। मैं ज्यादातर गैर-जीसी आधारित पर्यावरण (जैसे: iPhone) से संबंधित हूं।

स्कॉट के ब्लॉग से सीधे:

"असाइन किया गया कीवर्ड एक सेटर उत्पन्न करेगा जो कॉपी करने या उसे बनाए रखने के बजाय सीधे इंस्टेंस वैरिएबल को वैल्यू प्रदान करता है। यह आदिम प्रकारों जैसे NSInteger और CGFloat, या ऐसी वस्तुओं के लिए सबसे अच्छा है जो आप सीधे नहीं रखते हैं, जैसे प्रतिनिधि।"

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

क्या कोई आगे बता सकता है कि मैं कहां / क्यों गलत हूं, इसलिए मैं इस सामान्य प्रतिमान को ऑब्जेक्टिव-सी 2.0 प्रोग्रामिंग में असाइन किए गए प्रॉपर्टी पर उपयोग करने के बजाय प्रतिनिधियों पर रख सकता हूं?

धन्यवाद!


"डेलीगेट्स" और बिना "आईफ़ोन" के साथ फिर से जुड़े।
क्विन टेलर

प्रत्यायोजन को कॉपी के बजाय (NSString की तरह) क्यों सौंपा गया है
OMGPOP

जवाबों:


175

प्रतिनिधियों को बनाए रखने से बचने का कारण यह है कि आपको एक चक्र बनाए रखने से बचने की आवश्यकता है:

A, B A को स्वयं B के प्रतिनिधि के रूप में सेट करता है ... A इसके स्वामी द्वारा जारी किया जाता है

यदि B ने A को बनाए रखा था, तो A को जारी नहीं किया जाएगा, क्योंकि B का मालिक A है, इस प्रकार A के डीलॉक को कभी भी कॉल नहीं किया जाएगा, जिससे A और B दोनों लीक हो जाएंगे ।

आपको ए के चले जाने की चिंता नहीं करनी चाहिए क्योंकि यह बी का मालिक है और इस तरह से इससे छुटकारा मिल जाता है।


मैं सहमत नहीं हूँ, माइक। मुझे सिर्फ एक समस्या मिली जहां एक मॉडल के पास एक प्रतिनिधि होता है जो मॉडल को खारिज करता है। लेकिन जब मैं मोडल में मेमोरी चेतावनी देता हूं, तो यह प्रतिनिधि को जारी करता है। फिर जब मैं अपने मोडल को खारिज करने जाता हूं, तो प्रतिनिधि शून्य हो जाता है। दुर्घटना।
पॉल शापिरो

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

2
आपका कोड कभी भी इस तरह से नहीं लिखा जाना चाहिए कि एक शून्य प्रतिनिधि दुर्घटना का कारण बने। केवल मालिक की वस्तु का ही संदर्भ होना चाहिए। डीलक्लॉक करने पर, इसे जारी करने से पहले स्वामित्व वाली वस्तुओं के प्रतिनिधियों को शून्य पर सेट करना होगा। फिर निल प्रतिनिधि को भेजे गए किसी भी संदेश को अनदेखा कर दिया जाता है। किसी संदेश में कोई nil ऑब्जेक्ट पास करना , हालांकि क्रैश हो सकता है। बस सुनिश्चित करें कि आप प्रतिनिधियों के साथ इस तरह से व्यवहार नहीं करते हैं।
डेविड गिश

रुको - क्या weakयह नहीं है? सवाल यह है कि assignइसके बजाय उपयोग क्यों है weak?
wcochran

3
@wcochran: नहीं, इस सवाल का उपयोग assignकरने के बजाय क्यों है retain। सवाल एआरसी से पुराना है; weakऔर strong(बाद वाले का पर्यायवाची retain) ARC के पेश होने तक मौजूद नहीं था। आपको अपने प्रश्न को weakबनाम assignअलग से पूछना चाहिए ।
पीटर होसी

44

क्योंकि प्रतिनिधि संदेश भेजने वाली वस्तु प्रतिनिधि के पास नहीं है।

कई बार, यह दूसरा तरीका है, जब कोई नियंत्रक स्वयं को किसी दृश्य या विंडो के प्रतिनिधि के रूप में सेट करता है: नियंत्रक दृश्य / विंडो का स्वामी होता है, इसलिए यदि दृश्य / विंडो के पास उसके प्रतिनिधि का स्वामित्व है, तो दोनों ऑब्जेक्ट एक-दूसरे के मालिक होंगे। यह, निश्चित रूप से, एक अनुरक्षण चक्र है, समान परिणाम के साथ रिसाव के समान (ऐसी वस्तुएं जिन्हें मृत होना चाहिए जिंदा रहना चाहिए)।

अन्य बार, वस्तुएं सहकर्मी होती हैं: न तो कोई दूसरे का मालिक होता है, शायद इसलिए कि वे दोनों एक ही तीसरी वस्तु के मालिक हैं।

किसी भी तरह से, प्रतिनिधि के साथ वस्तु को अपने प्रतिनिधि को नहीं रखना चाहिए।

(वैसे, कम से कम एक अपवाद है। मुझे याद नहीं है कि यह क्या था, और मुझे नहीं लगता कि इसके लिए एक अच्छा कारण था।)


परिशिष्ट (2012-05-19 जोड़ा गया): एआरसी के तहत, आपको weakइसके बजाय उपयोग करना चाहिए assign। कमजोर संदर्भ nilस्वचालित रूप से तब सेट हो जाते हैं जब ऑब्जेक्ट मर जाता है, इस संभावना को समाप्त कर देता है कि प्रतिनिधि ऑब्जेक्ट मृत प्रतिनिधि को संदेश भेजना समाप्त कर देगा।

यदि आप किसी कारण से एआरसी से दूर रह रहे हैं, तो कम से कम उन assignगुणों को बदलें unsafe_unretainedजो ऑब्जेक्ट को इंगित करते हैं , जो स्पष्ट करते हैं कि यह ऑब्जेक्ट के लिए अप्राप्य लेकिन गैर-शून्य संदर्भ है।

assign एआरसी और एमआरसी दोनों के तहत गैर-वस्तु मूल्यों के लिए उपयुक्त है।


13
NSURLConnectionअपना प्रतिनिधि रखता है।

हां, उपयोग करें weak, लेकिन यह मूल प्रश्न का उत्तर नहीं देता है: Apple assignइसके बजाय क्यों उपयोग करता है weak?
वाकोच्रान

@wcochran: मूल प्रश्न यह था कि "प्रतिनिधि गुणों को बनाए रखने केassign बजाय क्यों दिया जाता है "; यह पूछे जाने पर मौजूद नहीं था। आपका प्रश्न एक अलग है, जिसे आपको अलग से पूछना चाहिए। मुझे इसका उत्तर देने में खुशी होगी। weak
पीटर होसी

@wcochran और पीटर, कि सवाल कहीं और पूछा गया है?
श्री रोजर्स

17

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


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

2
क्योंकि कोई भी संदर्भ छोड़ दिया गया सेट, किसी वस्तु के डील-डौल होने के बाद अमान्य हो जाएगा (इस ओर इशारा करते हुए कि स्मृति अब अपेक्षित वस्तु के प्रकार के लिए आवंटित नहीं है) - और इस प्रकार यदि आप इसका उपयोग करने का प्रयास करते हैं तो दुर्घटना हो सकती है। डीबगर में इसका एक संकेत तब होता है जब डिबगर का दावा है कि कुछ चर का एक प्रकार है जो कि चर वास्तव में जैसा है उससे पूरी तरह से गलत लगता है।
केंडल हेल्मेस् ट्टर गेलनर

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

@Andrew: यह सच है, लेकिन अगर आप इसे हमेशा प्रतिनिधियों को खत्म करने के लिए अभ्यास करते हैं तो आप तब नहीं भूलेंगे जब यह मायने रखता है, या यदि आप गलती से एक आयोजित वस्तु को बनाए रखते हैं और यह वैसे भी आसपास रहता है। यदि आप प्रतिनिधि को बाहर निकालते हैं तो परिणाम एक रिसाव के बजाय एक दुर्घटना के बाद रिसाव है।
केंडल हेल्मसटेटर जेलर

1

इसके पीछे का एक कारण चक्र को बनाए रखने से बचना है। बस उस परिदृश्य से बचने के लिए जहां ए और बी दोनों ऑब्जेक्ट एक दूसरे को संदर्भित करते हैं और उनमें से कोई भी मेमोरी से जारी नहीं होता है।

Acutally असाइन NSInteger और CGFloat तरह आदिम प्रकार के लिए सबसे अच्छा है, या आप इस तरह के प्रतिनिधियों के रूप में सीधे खुद नहीं करते हैं, वस्तुओं।


यह ओपी के उद्धरण और क्रमशः स्वीकृत उत्तर से कॉपी किया गया है, है ना?
dakab
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.