2013-01-10 19 views
18

के माध्यम से उद्देश्य सी में एक विधि ओवरराइड निम्नलिखित उद्देश्य सी में काम कर रहा है:श्रेणी

// Base Class in ClassA.h and ClassA.m 
@interface ClassA : NSObject 
- (NSString *) myMethod; 
@end 
@implementation ClassA 
- (NSString*) myMethod { return @"A"; } 
@end 

//Category in ClassA+CategoryB.h and ClassA+CategoryB.m 
@interface ClassA (CategoryB) 
- (NSString *) myMethod; 
@end 
@implementation ClassA (CategoryB) 
- (NSString*) myMethod { return @"B"; } 
@end 

सवाल है, अगर मैं सिर्फ ClassA.h का आयात कर रहा हूँ और संदेश भेजें

[myClassA myMethod]; //returns B 

क्यों क्या यह B लौट रहा है? मैं ClassA + CategoryB का आयात नहीं कर रहा हूँ

भी futhrer, अगर मैं निम्नलिखित किया:

// Base Class in ClassA.h and ClassA.m 
@interface ClassA : NSObject 
- (NSString *) myMethod; 
- (NSString *) mySecondMethod; 
@end 
@implementation ClassA 
- (NSString*) myMethod { return @"A"; } 
- (NSString *) mySecondMethod { return [self myMethod]; } 
@end 

//Category in ClassA+CategoryB.h and ClassA+CategoryB.m 
@interface ClassA (CategoryB) 
- (NSString *) myMethod; 
@end 
@implementation ClassA (CategoryB) 
- (NSString*) myMethod { return @"B"; } 
@end 

और फोन mySecondMethod:

ClassA *a = [[ClassA alloc] init]; 
NSLog(@"%@",[a myMethod]); 

परिणाम अभी भी B हो जाएगा, हालांकि कोई नहीं जानता (कारण कोई आयात नहीं) श्रेणी कार्यान्वयन के ?!

मैं अपवादित था, केवल B वापस जाने के लिए अगर मैं श्रेणी का आयात किया गया था ...

इसलिए किसी भी संकेत की सराहना की।

+6

मुझे आपके प्रश्न का उत्तर नहीं पता है, लेकिन श्रेणियां आमतौर पर कक्षा में नए तरीकों को जोड़ने के लिए होती हैं, मौजूदा लोगों को ओवरराइड नहीं करने के लिए। यदि आप ऐसा करना चाहते हैं, तो आपको इसे उप-वर्ग करना चाहिए। – Levi

+1

श्रेणियों में ओवरराइडिंग विधियों के परिणाम अपरिभाषित व्यवहार में: बिंदु में मामला। – CodaFi

+1

धन्यवाद उत्तर आपके उत्तर के लिए, मुझे पता है कि मैं सीखने के उद्देश्यों के लिए उपरोक्त उदाहरण पर सवाल कर रहा था ... मुझे उम्मीद नहीं थी, इसलिए मैं पूछ रहा हूं। – Alexander

उत्तर

37

उद्देश्य-सी संदेश गतिशील है, इसका मतलब यह है कि इससे कोई फर्क नहीं पड़ता कि आप श्रेणी आयात करते हैं या नहीं। ऑब्जेक्ट संदेश प्राप्त करेगा और उस विधि को निष्पादित करेगा।

श्रेणी आपकी विधि को ओवरराइड कर रही है। इसका अर्थ यह है कि जब रनटाइम उस ऑब्जेक्ट को संदेश भेजता है, तो हमेशा आप ओवरराइड विधि पाएंगे, इससे कोई फर्क नहीं पड़ता कि आप क्या आयात करते हैं।

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

इसके अलावा इस पढ़ें:

बचें श्रेणी विधि नाम संघर्ष

तरीकों एक वर्ग में घोषित एक मौजूदा वर्ग के लिए जोड़ रहे हैं, इसलिए आप विधि के नाम के बारे में बहुत सावधान रहना चाहिए।

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

तो आपके मामले में आपको कोई समस्या नहीं है क्योंकि जैसा कि कहा गया है, उपयोगकर्ता परिभाषित वर्गों के साथ ऐसा होने की संभावना कम है। लेकिन आपको निश्चित रूप से श्रेणी लिखने के बजाय उप-वर्गीकरण का उपयोग करना चाहिए।

+0

का एक डुप्लिकेट है यह सच है और मुझे पता है, लेकिन मैं वास्तव में नहीं समझता पदानुक्रम - श्रेणी विधि के बजाय श्रेणी विधि कहा जा रहा है। मैं उम्मीद करता हूं कि यह दूसरी तरफ हो ... – Alexander

+0

इससे कोई फर्क नहीं पड़ता कि आप क्या लिंक करते हैं, श्रेणी संकलित है और वह विधि ओवरराइड है। रनटाइम ऑब्जेक्ट को एक संदेश भेजता है और हमेशा ओवरराइड विधि पाता है। –

+0

विधि को ओवरराइड करने के बजाय, कक्षा को स्वयं घुमाएं। यह सुरक्षित है। – Reaper

9

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

लेकिन आपको श्रेणी को ओवरराइड करने से बचना चाहिए।

आप 100% सुनिश्चित नहीं होंगे कि कौन सी विधि कॉल की जाएगी। यह कंपाइलर पर निर्भर करता है।

ऐप्पल दस्तावेज़ीकरण से।

हालांकि ऑब्जेक्टिव-सी भाषा वर्तमान में आप तरीकों वर्ग इनहेरिट करती है, या यहाँ तक कि तरीकों वर्ग इंटरफ़ेस में घोषित ओवरराइड करने के लिए एक वर्ग का उपयोग करने की अनुमति देता है, तो आप दृढ़ता से ऐसा करने से हतोत्साहित किया जाता है। एक श्रेणी उप-वर्ग के लिए एक विकल्प नहीं है। विधियों को ओवरराइड करने के लिए श्रेणी का उपयोग करने के लिए कई महत्वपूर्ण कमियां हैं: जब कोई श्रेणी किसी विरासत विधि को ओवरराइड करती है, तो श्रेणी में विधि सामान्य रूप से, संदेश को सुपर के माध्यम से विरासत में कार्यान्वित कर सकती है। हालांकि, यदि कोई श्रेणी श्रेणी की कक्षा में मौजूद किसी विधि को ओवरराइड करता है, तो मूल कार्यान्वयन का आह्वान करने का कोई तरीका नहीं है। एक श्रेणी समान वर्ग की किसी अन्य श्रेणी में घोषित विधियों को विश्वसनीय रूप से ओवरराइड नहीं कर सकती है। यह मुद्दा विशेष महत्व का है क्योंकि कई कोको कक्षाएं श्रेणियों का उपयोग करके लागू की जाती हैं। एक ढांचा-परिभाषित विधि जिसे आप ओवरराइड करने का प्रयास करते हैं, स्वयं को एक श्रेणी में लागू किया जा सकता है, और इसलिए कार्यान्वयन को प्राथमिकता दी जाती है। कुछ श्रेणी विधियों की उपस्थिति से सभी ढांचे में व्यवहार में परिवर्तन हो सकता है। उदाहरण के लिए, यदि आप विंडो को ओवरराइड करते हैं WillClose: NSObject पर एक श्रेणी में प्रतिनिधि विधि, आपके प्रोग्राम में सभी विंडो प्रतिनिधि तब श्रेणी विधि का उपयोग करके प्रतिक्रिया देते हैं; NSWindow के आपके सभी उदाहरणों का व्यवहार बदल सकता है। एक फ्रेमवर्क कक्षा में जो श्रेणियां आप जोड़ते हैं वे व्यवहार में रहस्यमय परिवर्तन कर सकते हैं और दुर्घटनाओं का कारण बन सकते हैं।

+0

हाँ आप बिल्कुल सही हैं और मुझे यह पता है। लेकिन क्या मेरा उदाहरण थोड़ा उलझन में नहीं है? श्रेणी विधि के बारे में कोई भी नहीं जानता लेकिन इसे बुलाया जा रहा है ?! जैसे मैंने कहा, मुझे उम्मीद नहीं थी कि इसे कॉल करने और घायल करने की उम्मीद क्यों है "श्रेणी विधि से अधिक प्राथमिकता दी गई है" – Alexander

+0

तो मूल रूप से आप कह रहे हैं, अन्य कंपाइलर अन्य आउटपुट संभव है? – Alexander

+0

आपको http://stackoverflow.com/questions/5272451/overriding-methods-using-categories-in-objective-c से आपका उत्तर मिला। इसके बारे में कुछ भी गलत नहीं है, लेकिन कम से कम लिंक सैनिटी की जांच करें! –

2

आपने इसे संकलित करके श्रेणी में परिभाषित कोड को स्पष्ट रूप से शामिल किया है।

यदि आप श्रेणी कोड को निष्पादित करने से बचाना चाहते हैं तो आपको श्रेणी कार्यान्वयन फ़ाइल को हटाकर इसे अपने लक्ष्य से हटा देना चाहिए। आपको लगता है कि से

Target-> बिल्ड चरण> संकलित सूत्रों का कहना है

कहा कि, आप कभी नहीं एक विधि ओवरराइड करने के लिए एक वर्ग का उपयोग करना चाहिए कर सकते हैं। यह एक बहुत बुरा अभ्यास है और यह नहीं है कि श्रेणियां किसके लिए हैं।

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