हां, instancetypeउन सभी मामलों में उपयोग करने के लाभ हैं जहां यह लागू होता है। मैं और अधिक विस्तार से समझाता हूं, लेकिन मुझे इस साहसिक कथन के साथ शुरू करने दें: instancetypeजब भी उपयुक्त हो, तब उपयोग करें , जब भी कोई वर्ग उसी वर्ग का उदाहरण देता है।
वास्तव में, इस विषय पर एप्पल अब क्या कहता है:
अपने कोड में, जहां उचित हो, idवापसी मूल्य के रूप में होने वाली घटनाओं को बदलें instancetype। यह आमतौर पर initतरीकों और वर्ग कारखाने के तरीकों के लिए मामला है । भले ही संकलक स्वचालित रूप से उन विधियों को परिवर्तित करता है जो "आवंटित," "init," या "नए" से शुरू होती हैं और वापसी का प्रकार होता idहै instancetype, यह अन्य विधियों को परिवर्तित नहीं करता है। उद्देश्य-सी सम्मेलन instancetypeसभी विधियों के लिए स्पष्ट रूप से लिखना है ।
उस रास्ते से, चलो आगे बढ़ते हैं और समझाते हैं कि यह एक अच्छा विचार क्यों है।
सबसे पहले, कुछ परिभाषाएँ:
@interface Foo:NSObject
- (id)initWithBar:(NSInteger)bar; // initializer
+ (id)fooWithBar:(NSInteger)bar; // class factory
@end
एक वर्ग कारखाने के लिए, आपको हमेशा उपयोग करना चाहिए instancetype। संकलक स्वचालित रूप से परिवर्तित नहीं होता idहै instancetype। वह idएक सामान्य वस्तु है। लेकिन अगर आप इसे बनाते हैं तो instancetypeसंकलक जानता है कि विधि किस प्रकार की वस्तु देती है।
यह एक शैक्षणिक समस्या नहीं है। उदाहरण के लिए, [[NSFileHandle fileHandleWithStandardOutput] writeData:formattedData]मैक ओएस एक्स ( केवल ) पर एक त्रुटि उत्पन्न करेगा , जिसे 'राइटडैट:' नाम के कई तरीके बेमेल परिणाम, पैरामीटर प्रकार या विशेषताओं के साथ मिलते हैं । कारण यह है कि दोनों NSFileHandle और NSURLHandle प्रदान करते हैं writeData:। चूंकि [NSFileHandle fileHandleWithStandardOutput]रिटर्न idए, संकलक निश्चित नहीं है कि किस वर्ग writeData:को बुलाया जा रहा है।
आपको इसके चारों ओर काम करने की आवश्यकता है:
[(NSFileHandle *)[NSFileHandle fileHandleWithStandardOutput] writeData:formattedData];
या:
NSFileHandle *fileHandle = [NSFileHandle fileHandleWithStandardOutput];
[fileHandle writeData:formattedData];
बेशक, बेहतर उपाय यह है कि रिटर्न ए घोषित fileHandleWithStandardOutputकिया जाए instancetype। फिर कास्ट या असाइनमेंट आवश्यक नहीं है।
(ध्यान दें कि iOS पर, यह उदाहरण केवल एक त्रुटि NSFileHandleप्रदान नहीं करेगा क्योंकि केवल एक ही writeData:उदाहरण उपलब्ध कराता है । अन्य उदाहरण मौजूद हैं, जैसे कि lengthएक CGFloatसे UILayoutSupportलेकिन एक NSUIntegerसे वापस NSString।)
नोट : जब से मैंने यह लिखा है, macOS हेडर को एक के NSFileHandleबजाय वापस करने के लिए संशोधित किया गया है id।
शुरुआती के लिए, यह अधिक जटिल है। जब आप यह टाइप करें:
- (id)initWithBar:(NSInteger)bar
... संकलक आपको इसके बजाय टाइप किया हुआ दिखाएगा:
- (instancetype)initWithBar:(NSInteger)bar
एआरसी के लिए यह आवश्यक था। यह क्लैंग भाषा एक्सटेंशन संबंधित परिणाम प्रकारों में वर्णित है । यही कारण है कि लोग आपको बताएंगे कि इसका उपयोग करना आवश्यक नहीं है instancetype, हालांकि मुझे लगता है कि आपको चाहिए। इस उत्तर का शेष भाग इससे संबंधित है।
तीन फायदे हैं:
- स्पष्ट। आपका कोड वही कर रहा है जो वह कहता है, बजाय कुछ और।
- पैटर्न। आप कई बार अच्छी आदतों का निर्माण कर रहे हैं जो मायने रखती है, जो मौजूद हैं।
- संगति। आपने अपने कोड में कुछ स्थिरता स्थापित की है, जो इसे और अधिक पठनीय बनाता है।
मुखर
यह सच है कि ए से लौटने का कोई तकनीकी लाभ नहीं है । लेकिन यह इसलिए है क्योंकि संकलक स्वचालित रूप से करने के लिए कनवर्ट करता है । आप इस विचित्रता पर भरोसा कर रहे हैं; जब आप लिख रहे हैं कि रिटर्न ए, संकलक इसे व्याख्या कर रहा है जैसे कि यह रिटर्न देता है ।instancetypeinitidinstancetypeinitidinstancetype
ये संकलक के बराबर हैं :
- (id)initWithBar:(NSInteger)bar;
- (instancetype)initWithBar:(NSInteger)bar;
ये आपकी आंखों के बराबर नहीं हैं। सबसे अच्छा, आप अंतर को अनदेखा करना सीखेंगे और उस पर स्किम करेंगे। यह कुछ ऐसा नहीं है जिसे आपको अनदेखा करना सीखना चाहिए।
पैटर्न
जबकि initअन्य तरीकों के साथ कोई अंतर नहीं है , जैसे ही आप एक क्लास फैक्ट्री को परिभाषित करते हैं, तो अंतर होता है ।
ये दोनों समतुल्य नहीं हैं:
+ (id)fooWithBar:(NSInteger)bar;
+ (instancetype)fooWithBar:(NSInteger)bar;
आप दूसरा रूप चाहते हैं। यदि आप instancetypeएक निर्माता के रिटर्न प्रकार के रूप में टाइप करने के लिए उपयोग किए जाते हैं , तो आपको यह हर बार सही मिलेगा।
संगति
अंत में, कल्पना करें कि क्या आप इसे एक साथ रखते हैं: आप एक initफंक्शन चाहते हैं और एक क्लास फैक्ट्री भी।
यदि आप के लिए उपयोग idकरते हैं init, तो आप इस तरह कोड के साथ समाप्त होते हैं:
- (id)initWithBar:(NSInteger)bar;
+ (instancetype)fooWithBar:(NSInteger)bar;
लेकिन अगर आप उपयोग करते हैं instancetype, तो आपको यह मिलता है:
- (instancetype)initWithBar:(NSInteger)bar;
+ (instancetype)fooWithBar:(NSInteger)bar;
यह अधिक सुसंगत और अधिक पठनीय है। वे उसी चीज को वापस करते हैं, और अब यह स्पष्ट है।
निष्कर्ष
जब तक आप जानबूझकर पुराने कंपाइलरों के लिए कोड नहीं लिख रहे हैं, तब तक आपको instancetypeउचित उपयोग करना चाहिए ।
आपको एक संदेश लिखने से पहले संकोच करना चाहिए जो रिटर्न करता है id। अपने आप से पूछें: क्या यह इस वर्ग का एक उदाहरण है? यदि हां, तो यह एक है instancetype।
निश्चित रूप से ऐसे मामले हैं जहां आपको वापस जाने की आवश्यकता है id, लेकिन आप शायद instancetypeअधिक बार उपयोग करेंगे ।