2009-09-10 18 views
24

मैं एक उद्देश्य सी कक्षा में एक विधि को ओवरराइड करना चाहता हूं जिसके पास मेरा स्रोत नहीं है।एक उद्देश्य सी श्रेणी में सुपर का उपयोग कर?

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

जब भी मैं इसे आजमाता हूं, मेरी विधि को बुलाया जाता है, लेकिन "सुपर" शून्य है ... कोई विचार क्यों? मैं एक्सकोड 2.2 एसडीके के साथ आईफोन विकास कर रहा हूं। मैं निश्चित रूप से एक वर्ग के उदाहरण के साथ काम कर रहा हूं, और कक्षा की विधि एक उदाहरण विधि है।

@implementation SampleClass (filePathResolver) 
-(NSString*) fullPathFromRelativePath:(NSString*) relPath 
{ 
    NSString *result = [super fullPathFromRelativePath: relPath]; 

    ... do some stuff with the old result 

    return result; 
} 

नोट और स्पष्टीकरण: मैं ऐप्पल डॉक्स में जो देख सकता हूं, उससे मुझे लगता है कि इसकी अनुमति दी जानी चाहिए?

Categories docs at developer.apple.com: एक वर्ग एक विरासत विधि को ओवरराइड करता है, श्रेणी में विधि, हमेशा की तरह, विरासत में मिला कार्यान्वयन संदेश सुपर करने के लिए के माध्यम से आह्वान कर सकते हैं। हालांकि, यदि कोई श्रेणी श्रेणी की कक्षा में मौजूद पहले से मौजूद एक विधि को ओवरराइड करता है, तो मूल कार्यान्वयन को आमंत्रित करने का कोई तरीका नहीं है।

+0

आप कभी भी इस के लिए एक समाधान मिला? मैं पाठ पैरामीटर को संशोधित करने की कोशिश कर रहा हूं क्योंकि इसे UILabel के सेटटेक्स्ट: विधि में पारित किया गया है। मैं UILabel (विशाल कोडबेस) को उपclass नहीं करना चाहता, इसलिए एक श्रेणी सबसे अधिक उपयुक्त है। मुझे भी लगता है कि सुपर सेट टेक्स्ट को कॉल करना चाल होगा, अगर सुपर ऑब्जेक्ट वास्तव में यूआईएलएबल था, लेकिन फिर, यह संभवतः श्रेणी में परिभाषित एक अनंत लूप कॉलिंग सेटटेक्स्ट की ओर ले जाएगा। तो यह स्पष्ट है कि यह शायद एक श्रेणी के लिए एक असंभव काम है। –

+0

हे! इस पृष्ठ पर जो पोस्ट किया गया है उससे मुझे कोई अन्य समाधान नहीं मिला। विधि स्विजलिंग, या किसी श्रेणी में एक अलग विधि का उपयोग करें ;-( –

उत्तर

28

श्रेणियाँ मूल वर्ग का विस्तार करते हैं, लेकिन वे इसे उपclass नहीं करते हैं, इसलिए super पर कॉल विधि नहीं मिलती है।

जो आप चाहते हैं उसे Method Swizzling कहा जाता है। लेकिन ध्यान रखें कि आपका कोड कुछ तोड़ सकता है। पुराने उद्देश्य-सी रनटाइम में विधि स्विजलिंग के बारे में Theocacao written by Scot Stevenson पर एक आलेख है, Cocoa with Love by Matt Gallagher में नए उद्देश्य-सी 2.0 रनटाइम में विधि स्विजलिंग के बारे में एक लेख है और इसके लिए एक सरल प्रतिस्थापन है।

वैकल्पिक रूप से, आप वर्ग को उपclass कर सकते हैं और फिर सुपरक्लास का उपयोग करने के लिए उपclass का उपयोग करें या + (void)poseAsClass:(Class)aClass का उपयोग करें। एप्पल लिखते हैं:

एक विधि एक मुद्राओं का वर्ग द्वारा परिभाषित, super के लिए एक संदेश के माध्यम से, सुपर क्लास विधि शामिल कर सकते हैं यह ओवरराइड।

ध्यान रखें कि एप्पल मैक ओएस एक्स 10.5 में poseAsClass: त्याग दिया है।

+0

मुझे कुछ हद तक परेशान है कि "स्विजलिंग" नामक एक प्रोग्रामिंग अवधारणा है। हालांकि, यह एक दिलचस्प अवधारणा है। –

+1

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

+0

केवल, आप वास्तव में समस्या को हल करने के लिए एकमात्र संभव तरीका नहीं है जब तक कि आप समस्या को हल करने का एकमात्र संभव तरीका नहीं है। फिर भी, पता है कि झुकाव नाजुकता के गुच्छा के साथ आता है और रखरखाव के मुद्दों। – bbum

8

आप इस वर्ग के खिलाफ कोडिंग की जाएगी, तो बस कुछ अपने कोड का उपयोग कर सकते करने के लिए चयनकर्ता नाम बदलें, और self पर मूल चयनकर्ता फोन:

@implementation SampleClass (filePathResolver) 
-(NSString*) myFullPathFromRelativePath:(NSString*) relPath 
{ 
    NSString *result = [self fullPathFromRelativePath: relPath]; 

    ... do some stuff with the old result 

    return result; 
} 

आप इस के डिफ़ॉल्ट कार्यान्वयन ओवरराइड करने के लिए चाहते हैं उस वर्ग के लिए चयनकर्ता, आपको method swizzling दृष्टिकोण का उपयोग करने की आवश्यकता होगी।

+0

हाँ है, मैं उस वर्ग के खिलाफ लिखे गए सभी कोड को नियंत्रित नहीं करता ... इसलिए यह मेरे लिए काफी काम नहीं करता है, लेकिन सुझाव के लिए धन्यवाद! –

+1

^ehm, हाँ यह करता है। विधि swizzling kinda एक विशाल हैक और अपने कार्यक्रम के संभावित भविष्य के ब्रेक प्वाइंट की तरह लगता है - लेकिन यह उस स्थिति में काम करना चाहिए, जहां कक्षा के खिलाफ लिखे गए कोड पर आपका नियंत्रण नहीं है। – n13

+0

अच्छी तरह से मेरा मतलब है कि कोई अन्य कोड है जिसे मैं उस वर्ग पर "fullPathFromRelativePath" पर कॉल नहीं करता हूं। मैं नहीं बदल सकता कि दूसरा कोड क्या करता है, इसलिए इस मामले में swizzling मेरी मदद नहीं करेगा। –

1

बिल्कुल श्रेणी में नहीं है लेकिन रनटाइम पर गतिशील रूप से विधि जोड़कर एक समाधान है।अपने लेख में शमूएल Défago एक साफ रास्ता ब्लॉक छोटा सा भूत कार्यान्वयन सुपर बुला बनाने के लिए का वर्णन करता है, उसके मूल लेख पाया जा सकता है here

प्रासंगिक कोड है:

#import <objc/runtime.h> 
#import <objc/message.h> 

    const char *types = method_getTypeEncoding(class_getInstanceMethod(clazz, selector)); 
    class_addMethod(clazz, selector, imp_implementationWithBlock(^(__unsafe_unretained id self, va_list argp) { 
     struct objc_super super = { 
      .receiver = self, 
      .super_class = class_getSuperclass(clazz) 
     }; 

     id (*objc_msgSendSuper_typed)(struct objc_super *, SEL, va_list) = (void *)&objc_msgSendSuper; 
     return objc_msgSendSuper_typed(&super, selector, argp); 
    }), types);