2009-12-01 7 views
11

जब भी मैं अपने कोड में एक विधि लागू करता हूं जो एक से अधिक कक्षाओं की वस्तुओं को स्वीकार या वापस कर सकता है, तो मैं हमेशा उपलब्ध सबसे विशिष्ट सुपरक्लास का उपयोग करने का प्रयास करता हूं। उदाहरण के लिए, यदि मैं एक ऐसे तरीके को लागू करने जा रहा था जो उसके इनपुट के आधार पर एक एनएसएआरएआर * या एनएस डिक्शनरी * वापस कर सकता है, तो मैं उस विधि को एनएसओब्जेक्ट * का रिटर्न प्रकार दूंगा, क्योंकि यह सबसे प्रत्यक्ष आम सुपरक्लास है।एक विधि हस्ताक्षर में (आईडी) का उपयोग क्यों करें (NSObject *) अधिक सटीक होगा?

@interface MyParser() 
- (BOOL)stringExpressesKeyValuePairs:(NSString *)string; 
- (BOOL)stringExpressesAListOfEntities:(NSString *)string; 
- (NSArray *)parseArrayFromString:(NSString *)string; 
- (NSDictionary *)parseDictionaryFromString:(NSString *)string; 
@end 

@implementation MyParser 
- (NSObject *)parseString:(NSString *)string { 
    if ([self stringExpressesKeyValuePairs:string]) { 
     return [self parseDictionaryFromString:string]; 
    } 
    else if ([self stringExpressesAListOfEntities:string]) { 
     return [self parseArrayFromString:string]; 
    } 
} 
// etc... 
@end 

मैं फाउंडेशन और अन्य API में कई मामलों में जहां कुछ विधि हस्ताक्षर में एप्पल का उपयोग करता है (आईडी) जब (NSObject *) और अधिक सटीक होगा ध्यान दिया है: यहाँ एक उदाहरण है। उदाहरण के लिए, यहाँ NSPropertyListSerialization की एक विधि है:

+ (id)propertyListFromData:(NSData *)data 
      mutabilityOption:(NSPropertyListMutabilityOptions)opt 
        format:(NSPropertyListFormat *)format 
      errorDescription:(NSString **)errorString 

इस विधि से संभावित वापसी प्रकार NSData, NSString, NSArray, NSDictionary, NSDate, और NSNumber हैं। ऐसा लगता है कि एक वापसी प्रकार (एनएसओब्जेक्ट *) (आईडी) से बेहतर विकल्प होगा, क्योंकि कॉलर एनएसओब्जेक्ट विधियों को कॉल करने में सक्षम होगा जैसे कि टाइप-कास्ट के बिना बनाए रखें।

मैं आम तौर पर आधिकारिक ढांचे द्वारा स्थापित मुहावरों का अनुकरण करने की कोशिश करता हूं, लेकिन मैं यह भी समझना चाहता हूं कि उन्हें क्या प्रेरित करता है। मुझे यकीन है कि ऐप्पल के पास इस तरह के मामलों में (आईडी) का उपयोग करने के लिए कुछ वैध कारण है, लेकिन मैं इसे देख नहीं रहा हूं। मैं क्या खो रहा हूँ?

+0

एनएसपीरोक्सी एनएसओब्जेक्ट नहीं है। एनएसओब्जेक्ट एकमात्र मूल वर्ग नहीं है, इसलिए यह एक सुरक्षित धारणा नहीं है कि सब कुछ इसके उप-वर्ग होगा। –

उत्तर

8

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

1

आप पहले से ही कॉल किए बिना टाइप आईडी के पॉइंटर्स पर कॉल कर सकते हैं। यदि आप एक विशिष्ट सुपरक्लास प्रकार का उपयोग करते हैं, तो आपको संकलक चेतावनियों से बचने के लिए हर बार जब आप सबक्लास की विधि को कॉल करते हैं तो पॉइंटर को डालना होगा। आईडी का उपयोग करें ताकि संकलक आपको चेतावनी न दे और आपके इरादे को बेहतर ढंग से इंगित करे।

19

कारण है कि (आईडी) विधि घोषणाओं में प्रयोग किया जाता है दो गुना है:

(1) विधि लेने के लिए या किसी भी प्रकार के वापस आ सकते हैं। एनएसएआरएआरई में कोई यादृच्छिक वस्तु है और, इस प्रकार, objectAtIndex: किसी भी यादृच्छिक प्रकार की वस्तु को वापस कर देगा। इसे NSObject* या id <NSObject> पर दो कारणों से गलत किया जाएगा; सबसे पहले, एक ऐरे में गैर NSObject उप-वर्ग शामिल हो सकते हैं जब तक वे एक निश्चित छोटे सेट विधि को लागू करते हैं और दूसरी बात, एक विशिष्ट रिटर्न प्रकार को कास्टिंग की आवश्यकता होती है।

(2) उद्देश्य-सी कॉन्वर्सेंट घोषणाओं का समर्थन नहीं करता है। पर विचार करें:

@interface NSArray:NSObject 
+ (id) array; 
@end 

अब, आप NSArray और NSMutableArray दोनों पर +array कॉल कर सकते हैं। पूर्व एक अपरिवर्तनीय सरणी और उत्तरार्द्ध एक उत्परिवर्तनीय सरणी देता है। उद्देश्य-सी की कॉन्वर्सेंट घोषणा समर्थन की कमी के कारण, यदि उपरोक्त को (NSArray*) लौटने के रूप में घोषित किया गया था, तो सबक्लास विधि के ग्राहकों को `(NSMutableArray *) पर जाना होगा। बदसूरत, नाजुक, और त्रुटि प्रवण। इस प्रकार, सामान्य प्रकार का उपयोग करना आम तौर पर सबसे सरल समाधान है।

तो ... यदि आप एक ऐसी विधि घोषित कर रहे हैं जो एक विशिष्ट वर्ग का उदाहरण देता है, तो टाइपकास्ट स्पष्ट रूप से। यदि आप एक ऐसी विधि घोषित कर रहे हैं जिसे ओवरराइड किया जाएगा और ओवरराइड एक सबक्लास और लौटा सकता है, तो यह तथ्य है कि यह सबक्लास लौटाता है, ग्राहकों के सामने आ जाएगा, फिर (id) का उपयोग करें।

कोई बग फ़ाइल करने की आवश्यकता नहीं है - पहले से ही कई हैं।


ध्यान दें कि ObjC अब instancetype कीवर्ड के माध्यम से सह विचरण समर्थन सीमित है।

आईई। NSArray के + सरणी विधि अब के रूप में घोषित किया जा सकता है:

+ (instancetype) array; 

और संकलक [NSMutableArray array] इलाज के रूप में लौटने एक NSMutableArray* जबकि [NSArray array]NSArray* लौटने के रूप में विचार किया जाएगा।

1

(आईडी) अक्सर ऑब्जेक्ट को अधिक आसानी से उपclass करने के लिए सक्षम करने के लिए भी लौटा दिया जाता है। उदाहरण के लिए, प्रारंभकर्ता और सुविधा विधियों में, लौटने (आईडी) का अर्थ है कि किसी भी उप-वर्ग को सुपरक्लास के तरीकों को ओवरराइड करने की आवश्यकता नहीं होती है जब तक ऐसा करने का कोई विशिष्ट कारण न हो।

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