ऑब्जेक्टिव-सी में मुझे यह जांच करनी चाहिए कि क्या आत्म = [सुपर इनिट] शून्य नहीं है?


165

मेरे पास Objective-C में init के तरीके लिखने के बारे में एक सामान्य सवाल है।

मैं इसे हर जगह देखता हूं (Apple का कोड, किताबें, ओपन सोर्स कोड इत्यादि) कि एक init मेथड को जांचना चाहिए कि क्या self = [super init] आरंभीकरण के साथ जारी रखने से पहले शून्य नहीं है।

एक init विधि के लिए डिफ़ॉल्ट Apple टेम्प्लेट है:

- (id) init
{
    self = [super init];

    if (self != nil)
    {
        // your code here
    }

    return self;
}

क्यों?

मेरा मतलब है कि जब init कभी नील को वापस करने जा रहा है? अगर मैंने NSObject पर init बुलाया और वापस शून्य हो गया, तो कुछ वास्तव में खराब होना चाहिए? और उस मामले में, आप एक कार्यक्रम भी नहीं लिख सकते हैं ...

क्या यह वास्तव में सामान्य है कि एक वर्ग 'init पद्धति शून्य हो सकती है? यदि हां, तो किस मामले में, और क्यों?


1
विल शिप्ली ने कुछ समय पहले इससे संबंधित एक लेख पोस्ट किया था। [स्व = [बेवकूफ init]?] ( wilshipley.com/blog/2005/07/self-stupid-init.html ) टिप्पणियों के माध्यम से भी पढ़ें, कुछ अच्छी चीजें।
रयान टाउनशेंड

6
आप विल शिपले या माइक ऐश या मैट गैलाघर पूछ सकते हैं । किसी भी तरह से, यह एक बहस विषय का कुछ है। लेकिन आमतौर पर एप्पल के मुहावरों के साथ रहना अच्छा होता है ... यह उनका फ्रेमवर्क है, आखिरकार।
jbrennan

1
ऐसा लगता है कि विली एक मामले में आँख बंद करके आत्म-विश्वास नहीं कर रहा था, यह जानते हुए कि [सुपर इनिट] रिसीवर वापस नहीं कर सकता है।
जसारीन

3
विल ने अपने विचारों को बदल दिया है क्योंकि यह पद मूल रूप से बनाया गया था।
bbum

5
मैंने इस प्रश्न को कुछ समय पहले देखा था और इसे फिर से पाया। उत्तम। +1
डैन रोसेनस्टार्क

जवाबों:


53

उदाहरण के लिए:

[[NSData alloc] initWithContentsOfFile:@"this/path/doesn't/exist/"];
[[NSImage alloc] initWithContentsOfFile:@"unsupportedFormat.sjt"];
[NSImage imageNamed:@"AnImageThatIsntInTheImageCache"];

... और इसी तरह। (नोट: अगर फ़ाइल मौजूद नहीं है तो NSData अपवाद फेंक सकता है)। काफी कुछ ऐसे क्षेत्र हैं जहाँ समस्या होने पर शून्य वापस करना अपेक्षित व्यवहार है, और इस वजह से यह निरंतरता के लिए, हर समय शून्य के लिए जाँच करने के लिए मानक अभ्यास है।


10
हां, लेकिन यह संबंधित वर्ग की init विधि नहीं है। NSData को NSObject से विरासत में मिला है। NSData जाँच करता है कि क्या [सुपर init] शून्य लौटाता है? यही मैं यहाँ पूछ रहा हूँ। क्षमा करें अगर मैं स्पष्ट नहीं था ...
जसारीन

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

7
मुझे संदेह है कि NSObject init कभी भी, किसी भी मामले में शून्य वापस कर सकता है। यदि आप स्मृति से बाहर हैं, तो आवंटन विफल हो जाएगा, लेकिन अगर यह सफल होता है, तो मुझे संदेह है कि यह init विफल हो सकता है - NSObject के पास कक्षा को छोड़कर कोई भी उदाहरण चर नहीं है। GNUStep में, इसे केवल "रिटर्न सेल्फ" के रूप में लागू किया गया है, और मैक पर असंतुष्ट होना समान दिखता है। यह सब, निश्चित रूप से, अप्रासंगिक है - बस मानक मुहावरे का पालन करें और आपको इस बारे में चिंता करने की ज़रूरत नहीं है कि यह हो सकता है या नहीं।
पीटर एन लुईस

9
मैं सर्वोत्तम प्रथाओं का पालन नहीं करने पर तुला हुआ हूं। हालाँकि, मैं यह जानना चाहूंगा कि वे पहले स्थान पर सर्वश्रेष्ठ अभ्यास क्यों हैं। यह एक टॉवर से कूदने के लिए कहा जा रहा है। आप आगे नहीं जाते हैं और जब तक आपको पता नहीं है ऐसा क्यों करते हैं। क्या बड़े पैमाने पर नकद इनाम के साथ, तल पर उतरने के लिए एक बड़ा, मुलायम तकिया है? अगर मुझे पता था कि मैं कूद जाऊंगा। यदि नहीं, तो मैं नहीं करूंगा। मैं सिर्फ आँख बंद करके बिना किसी अभ्यास का अनुसरण नहीं करना चाहता, क्योंकि मैं इसका पालन कर रहा हूँ ...
जसरीन

4
यदि रिटर्न एनआईएल आवंटित किया जाता है, तो एनआईएल को शून्य पर भेजा जाता है, जिसके परिणामस्वरूप हमेशा शून्य हो जाएगा, यह स्वयं को शून्य होने के साथ समाप्त करता है।
टी।

50

यह विशेष मुहावरा मानक है क्योंकि यह सभी मामलों में काम करता है।

असामान्य होने पर, ऐसे मामले होंगे जहां ...

[super init];

... एक अलग उदाहरण देता है, इस प्रकार स्वयं को असाइनमेंट की आवश्यकता होती है।

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

लब्बोलुआब यह है कि यह उपयोग करने के लिए प्रलेखित सही पैटर्न है और, यदि आप इसका उपयोग नहीं कर रहे हैं, तो आप इसे गलत कर रहे हैं।


3
क्या यह अभी भी अशक्तता के प्रकाशकों के प्रकाश में सच है? अगर मेरे सुपरक्लास का इनिशियलाइज़र नॉन-न्यूल है तो क्या यह वास्तव में जांचने के लिए अतिरिक्त अव्यवस्था के लायक है? (हालांकि NSObject खुद को इसके -initप्रभाव के लिए कोई भी प्रतीत नहीं होता है ...)
natevw

क्या कभी ऐसा मामला सामने [super init]आया है, जब डायरेक्ट सुपरक्लास होने पर रिटर्न मिलता है NSObject? क्या यह ऐसा मामला नहीं है जहां "सब कुछ टूट गया है?"
डैन रोसेन्स्टार्क

1
@DanRosenstark नहीं तो NSObjectसीधे सुपरक्लास है । लेकिन ... यहां तक ​​कि अगर आप NSObjectसीधे सुपरक्लास के रूप में घोषित करते हैं , तो कुछ को रनटाइम पर संशोधित किया जा सकता है जैसे कि NSObjectकार्यान्वयन initवास्तव में नहीं कहा जाता है।
bbum

1
बहुत बहुत धन्यवाद @bbum, यह वास्तव में मुझे कुछ बग फिक्सिंग में उन्मुख करने में मदद की। कुछ चीजों को शासन करने के लिए अच्छा है!
डैन रोसेनस्टार्क

26

मुझे लगता है, ज्यादातर कक्षाओं में, अगर [सुपर इनिट] से रिटर्न वैल्यू शून्य है और आप इसे जांचते हैं, जैसा कि मानक प्रथाओं द्वारा अनुशंसित है, और फिर समय से पहले वापस आ जाता है अगर शून्य, मूल रूप से आपका ऐप अभी भी सही ढंग से काम नहीं कर रहा है। आप, इसके बारे में सोचते भी है कि हालांकि, अगर (आत्म! = शून्य) चेक नहीं है, अपने वर्ग के समुचित संचालन के लिए, समय आप वास्तव में की 99.99% कर स्वयं की जरूरत गैर शून्य होने के लिए। अब, मान लीजिए कि किसी भी कारण से, [सुपर इनिट] ने शून्य कर दिया, मूल रूप से नील के खिलाफ आपका चेक मूल रूप से आपकी कक्षा के कॉलर को रुपये दे रहा है, जहां यह संभावना वैसे भी विफल हो जाएगी, क्योंकि यह स्वाभाविक रूप से यह मान लेगा कि कॉल था सफल।

असल में, मुझे जो मिल रहा है, वह 99.99% समय है, अगर (स्व! = नील) आपको अधिक मजबूती के संदर्भ में कुछ भी नहीं खरीदता है, क्योंकि आप सिर्फ अपने चालान के लिए रुपये दे रहे हैं। वास्तव में इसे मजबूती से संभालने में सक्षम होने के लिए, आपको वास्तव में अपने पूरे कॉलिंग पदानुक्रम में चेक लगाने की आवश्यकता होगी। और फिर भी, केवल एक चीज जो आपको खरीदेगी वह यह है कि आपका ऐप थोड़ा और अधिक साफ / मजबूत रूप से विफल हो जाएगा। लेकिन यह अभी भी विफल होगा।

यदि एक पुस्तकालय वर्ग ने मनमाने ढंग से एक [सुपर init] के परिणामस्वरूप शून्य लौटने का फैसला किया है, तो आप बहुत अधिक च *** एड वैसे भी हैं, और यह एक संकेत है कि पुस्तकालय वर्ग के लेखक ने कार्यान्वयन की गलती की है।

मुझे लगता है कि यह एक विरासत कोडिंग सुझाव से अधिक है, जब एप्लिकेशन बहुत अधिक सीमित मेमोरी में चले गए।

लेकिन सी लेवल कोड के लिए, मैं अभी भी NULL पॉइंटर के खिलाफ मॉलॉक () के रिटर्न वैल्यू की जांच करूंगा। जबकि, ऑब्जेक्टिव-सी के लिए, जब तक मुझे इसके विपरीत साक्ष्य नहीं मिल जाते, मुझे लगता है कि मैं आम तौर पर if (स्व! = Nil) चेक को छोड़ देता हूँ। विसंगति क्यों?

क्योंकि, कुछ मामलों में, सी और मॉलॉक स्तरों पर, आप वास्तव में आंशिक रूप से ठीक हो सकते हैं। जबकि मैं 99.99% मामलों में ऑब्जेक्टिव-सी के बारे में सोचता हूं, अगर [सुपर इनिट] शून्य करता है, तो आप मूल रूप से एफ एड हैं, भले ही आप इसे संभालने की कोशिश करें। आप एप्लिकेशन को क्रैश होने और उसके बाद के साथ सौदा करने के लिए भी कह सकते हैं।


6
सही बोला हुआ है। मुझे भी वह पता हैं।
रोजर सीएस वर्नरसन

3
+1 मैं पूरी तरह सहमत हूं। बस एक मामूली नोट: मेरा मानना ​​है कि पैटर्न कई बार ऐसा परिणाम होता है जहां आवंटन अधिक बार विफल होता है। आवंटन आमतौर पर पहले से ही उस समय किया जाता है जब इनिट कहा जाता है। यदि आवंटन विफल हो जाता है, तो init को भी नहीं बुलाया जाएगा।
निकोलाई रुहे

8

यह उपरोक्त टिप्पणियों का सारांश है।

मान लीजिए कि सुपरक्लास रिटर्न है nil। क्या होने वाला है?

यदि आप सम्मेलनों का पालन नहीं करते हैं

आपका कोड आपकी initविधि के बीच में क्रैश होने वाला है । (जब तक initकोई महत्व का न हो)

यदि आप सम्मेलनों का पालन करते हैं, तो यह नहीं जानते हुए कि सुपरक्लास शून्य वापस आ सकता है (ज्यादातर लोग यहां समाप्त होते हैं)

आपका कोड बाद में कुछ हद तक दुर्घटनाग्रस्त होने वाला है, क्योंकि आपका उदाहरण है nil, जहाँ आपको कुछ अलग करने की उम्मीद थी। या आपके कार्यक्रम को दुर्घटनाग्रस्त होने के बिना अप्रत्याशित रूप से व्यवहार करना है। ओ प्यारे! क्या आप यह चाहते हैं? मुझे नहीं पता...

यदि आप सम्मेलनों का पालन करते हैं, तो स्वेच्छा से अपने उपवर्ग को शून्य पर लौटने की अनुमति दें

आपके कोड के दस्तावेज़ (!) में स्पष्ट रूप से लिखा होना चाहिए: "रिटर्न ... या नील", और इसे संभालने के लिए आपके बाकी कोड को तैयार करने की आवश्यकता है। अब समझ में आता है।


5
यहाँ दिलचस्प बात, मुझे लगता है, यह विकल्प # 1 स्पष्ट रूप से # 2 विकल्प के लिए बेहतर है। यदि वास्तव में ऐसी परिस्थितियां हैं, जिसमें आप अपने उपवर्ग को शून्य वापस करने के लिए चाहते हैं, तो # 3 को प्राथमिकता दी जानी है। यदि आपके कोड में बग के कारण कभी-कभी एकमात्र कारण होता है, तो # 1 का उपयोग करें। विकल्प # 2 का उपयोग करना आपके ऐप को बाद के समय तक विस्फोट करने में देरी कर रहा है, और जब आप इस त्रुटि को डीबग करने के लिए आते हैं, तो यह बहुत कठिन है। यह चुपचाप अपवादों को पकड़ने और उन्हें संभालने के बिना जारी रखने जैसा है।
मार्क एमी जूल 5'13

या आप स्विफ्ट पर जाएं और वैकल्पिक का उपयोग करें
एंड्रयूजबी

7

आमतौर पर, यदि आपकी कक्षा सीधे से आती है NSObject, तो आपको इसकी आवश्यकता नहीं होगी। हालाँकि, यह एक अच्छी आदत है कि अगर आपकी कक्षा अन्य कक्षाओं से आती है nil, तो उनके आरंभीकरण वापस आ सकते हैं , और यदि ऐसा है, तो आपका इनीशलाइज़र उस पर कब्जा कर सकता है और सही व्यवहार कर सकता है।

और हां, रिकॉर्ड के लिए, मैं सबसे अच्छे अभ्यास का पालन करता हूं और इसे अपनी सभी कक्षाओं पर लिखता हूं, यहां तक ​​कि सीधे से प्राप्त करने वाले भी NSObject


1
इसे ध्यान में रखते हुए, एक चर को इनिशियलाइज़ करने और उस पर फ़ंक्शंस को कॉल करने से पहले नील की जाँच करना अच्छा रहेगा? जैसेFoo *bar = [[Foo alloc] init]; if (bar) {[bar doStuff];}
dev_does_software

इनहेरिट करने से NSObjectइसकी गारंटी नहीं -initमिलती NSObjectहै, अगर आप GNUstep के पुराने संस्करणों (जैसे रिटर्न GSObject) में विदेशी रनटाइम की गिनती करते हैं, तो कोई फर्क नहीं पड़ता कि क्या है, एक चेक और एक असाइन।
मैक्सथन चान

3

आप सही हैं, आप अक्सर सिर्फ लिख सकते हैं [super init], लेकिन यह सिर्फ कुछ के उपवर्ग के लिए काम नहीं करेगा। लोग कोड की एक मानक लाइन को याद रखना पसंद करते हैं और हर समय इसका उपयोग करते हैं, तब भी जब यह केवल कभी-कभी आवश्यक होता है, और इस तरह हम मानक प्राप्त करते हैं if (self = [super init]), जो शून्य की वापसी की संभावना और वस्तु के selfवापस होने के अलावा किसी अन्य की संभावना को लेता है। खाते में।


3

एक सामान्य गलती लिखना है

self = [[super alloc] init];

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

self = [super init]; 

यदि उपवर्गों के सदस्यों को स्थापित करने से पहले पहले शुरू करने के लिए सुपर क्लास के सदस्यों (चर या अन्य ऑब्जेक्ट) की आवश्यकता होती है । अन्यथा objc रनटाइम उन सभी को 0 या शून्य करने के लिए प्रारंभ करता है । ( एएनएसआई सी के विपरीत, जो अक्सर उन्हें साफ करने के बिना स्मृति के टुकड़े आवंटित करता है )

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


2

यह जाँचना है कि इंतिज़ाम ने काम किया है, अगर यह कथन सही है अगर init पद्धति वापस नहीं लौटी है, तो इसका उद्देश्य सही ढंग से काम किए गए निर्माण की जाँच करना है। कुछ कारण जो मैं सोच सकता हूँ कि यह विफल हो सकता है इसका एक गलत init तरीका हो सकता है कि सुपर क्लास को इस तरह का या कुछ पता नहीं है, मुझे लगता है कि यह आम है। लेकिन अगर ऐसा होता है, तो इससे बेहतर कुछ भी नहीं हो सकता है कि एक दुर्घटना मैं इसकी हमेशा जाँच की गई है ...


यह है, लेकिन htey को एक साथ कहा जाता है, अगर एफिल को आवंटित किया जाता है तो क्या होगा?
डैनियल

मुझे लगता है कि यदि आबंटन विफल हो जाता है, तो इनिट को एनआईटी को भेजा जाएगा, बजाय इसके कि आप जिस भी क्लास को इनिट कह रहे हैं, उसका एक उदाहरण। उस स्थिति में, कुछ भी नहीं होगा, और कोई कोड भी परीक्षण के लिए निष्पादित नहीं किया जाएगा कि क्या [सुपर init] शून्य वापस आ गया है या नहीं।
जसरीन

2
मेमोरी आवंटन हमेशा + आवंटन में नहीं किया जाता है। वर्ग समूहों के मामले पर विचार करें; NSString को यह पता नहीं होता है कि इनिशियलाइज़र के आह्वान तक कौन से विशिष्ट उपवर्ग का उपयोग करना है।
bbum

1

OS X में, यह -[NSObject init]मेमोरी कारणों के कारण विफल होने की संभावना नहीं है। IOS के लिए भी ऐसा नहीं कहा जा सकता है।

इसके अलावा, यह लिखने के लिए अच्छा अभ्यास है जब किसी वर्ग को उप-वर्ग बनाते हुए nilजो भी कारण से वापस आ सकता है।


2
दोनों आईओएस और मैक ओएस पर -[NSObject init]है बहुत स्मृति कारणों की वजह से विफल के रूप में यह किसी भी स्मृति को आबंटित नहीं है संभावना नहीं है।
निकोलाई रुहे

मुझे लगता है कि वह आवंटन का मतलब है, init नहीं :)
थॉमस टेम्प्लेमन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.