2011-05-06 23 views
7

मैं कुछ गतिशील कोड लिखने की कोशिश कर रहा हूं जहां कोई उपयोगकर्ता किसी वर्ग के विशिष्ट उदाहरण से विधि को कॉल करने का प्रयास कर सकता है और इसे रनटाइम पर हल किया जा सकता है। जानकारी को पुनर्प्राप्त करने के लिए कार्यान्वयन मौजूद है लेकिन इसका उपयोग करने की विधि यह नहीं है क्योंकि यह प्रति उदाहरण आधार पर है।उद्देश्य-सी कार्य में class_addMethod केवल एक विशिष्ट उदाहरण पर कर सकते हैं?

उदाहरण के लिए, यदि कोई उपयोगकर्ता एक विधि "getSomething" नाम कौन सी क्लास में मौजूद नहीं है कॉल करना चाहते हो सकता है:

[someInstance getSomething] 

इस स्थिति में, मैं एक कार्यान्वयन का समाधान जो एक चर है करना चाहते हैं वापसी प्रकार जो केवल उस उदाहरण पर लागू होगा जिस पर काम किया जा रहा है। मैं उद्देश्य-सी से class_addMethod का उपयोग करने पर विचार कर रहा था लेकिन मैं अपने व्यवहार के 100% निश्चित नहीं हूं। दस्तावेज़ीकरण पर यह दावा करता है कि इसका उपयोग कक्षा या उदाहरण विधियों को जोड़ने के लिए किया जा सकता है। क्या इस वर्ग को कॉल करने के लिए विधि केवल विशिष्ट उदाहरण या कक्षा में जोड़ती है ताकि बाद में बनाए गए प्रत्येक इंस्टेंस पर विधि हो? मैंने यह भी पढ़ा कि एक बार विधि जोड़ने के बाद आप इसे हटा नहीं सकते हैं।

शायद मेरा दृष्टिकोण सही नहीं है इसलिए यदि कोई विकल्प ज्ञात है तो मैं इसकी सराहना करता हूं। मैं संदेश अग्रेषण का उपयोग नहीं कर सकता क्योंकि कोई वर्ग नहीं है जो पहले से लागू चयनकर्ता को समझता है।

उत्तर

0

मैं class_addMethod से परिचित नहीं हूँ, लेकिन शायद यह मदद कर सकते हैं के लिए स्पष्ट:

याद रखें कि ऑब्जेक्टिव-सी में आप नहीं "एक विधि को" हैं, लेकिन आप वास्तव में एक संदेश भेज रहे। तो यह करना सुरक्षित है: किसी भी तत्काल वस्तु पर [anyObject anyMethodName]। यह ऑब्जेक्ट संदेश का जवाब दे सकता है या नहीं।

आप यह जांच सकते हैं कि किसी ऑब्जेक्ट का उपयोग करके कोई ऑब्जेक्ट होगा या नहीं [किसी भी ऑब्जेक्ट प्रतिक्रियाओं का चयन करने वाला: @ चयनकर्ता (@ "anyMethodName")] जांचें, और यदि यह हाँ है, तो आगे बढ़ें और [anyObject anyMethodName] कॉल करें। मैं आपकी समस्या का वर्णन पूरी तरह से समझ नहीं पा रहा हूं लेकिन ऐसा लगता है कि आपके पास ऑब्जेक्ट से भरा विषम कंटेनर है जो कॉल का जवाब दे सकता है या नहीं। यह "जवाब देने के लिए चयनकर्ता:" कंटेनर में प्रत्येक ऑब्जेक्ट पर जांच उद्देश्य-सी में एक पूरी तरह से सामान्य चीज है और अच्छी डिजाइन की तरह लगता है

यदि प्रत्येक ऑब्जेक्ट कुछ अलग प्रकार का डेटा देता है, तो आप इसे 'आईडी' सामान्य प्रकार यही है, आईडी वापसी डेटा = [anyObject anyMethodName]; फिर, आप या तो रिटर्नडाटा पर आत्मनिरीक्षण का उपयोग कर सकते हैं, या आप 'anyObject' की श्रेणी के आधार पर चीजों को अलग-अलग संभाल सकते हैं, किसी भी ऑब्जेक्ट क्लास द्वारा चेक किया गया है;

तो की तरह,

if([anyObject class] == MyGreatClass) // recast data to MyGreatClassCoolReturnType

मुझे आशा है कि इस सवाल का

+0

मेरे प्रश्न का उत्तर देने के लिए समय निकालने के लिए धन्यवाद। यह वास्तव में वह नहीं है जिसे मैं ढूंढ रहा था लेकिन यह मुझे उन अन्य क्षेत्रों पर कुछ अंतर्दृष्टि देता है जिनके बारे में मैं अस्पष्ट था। – gtaborga

2

class_addMethod() का जवाब में मदद करता है एक वर्ग वस्तु या एक वर्ग विधि एक metaclass वस्तु करने के लिए एक उदाहरण विधि कहते हैं। दूसरे शब्दों में, आप कक्षा के एक उदाहरण के लिए कभी भी एक विधि नहीं जोड़ सकते हैं।

इसके बजाय, यदि आपको वास्तव में इस व्यवहार की आवश्यकता है, तो आप -forwardInvocation: लागू कर सकते हैं, जहां प्राप्त करने वाला ऑब्जेक्ट यह तय कर सकता है कि संदेश को पूरा करने के लिए पर्याप्त जानकारी है या नहीं। ध्यान दें कि -forwardInvocation: के कार्यान्वयन के लिए आम तौर पर -methodSignatureForSelector: और -respondsToSelector: को लागू करने की आवश्यकता होती है।,

- (void)addCustomMethodToObject:(id)object { 
    Class objectClass = object_getClass(object); 
    SEL selectorToOverride = ...; // this is the method name you want to override 

    NSString *newClassName = [NSString stringWithFormat:@"Custom_%@", NSStringFromClass(objectClass)]; 
    Class c = NSClassFromString(newClassName); 
    if (c == nil) { 
    // this class doesn't exist; create it 
    // allocate a new class 
    c = objc_allocateClassPair(objectClass, [newClassName UTF8String], 0); 
    // get the info on the method we're going to override 
    Method m = class_getInstanceMethod(objectClass, selectorToOverride); 
    // add the method to the new class 
    class_addMethod(c, selectorToOverride, (IMP)myCustomFunction, method_getTypeEncoding(m)); 
    // register the new class with the runtime 
    objc_registerClassPair(c); 
    } 
    // change the class of the object 
    object_setClass(object, c); 
} 

id myCustomFunction(id self, SEL _cmd, [other params...]) { 
    // this is the body of the instance-specific method 
    // you may call super to invoke the original implementation 
} 

यह करने के बाद, केवल object ओवरराइड विधि प्राप्त हुआ होगा क्योंकि यह केवल एक चीज खास वर्ग का एक उदाहरण है कि हो जाएगा:

7

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

हमेशा की तरह, हमेशा की तरह चेतावनी:

  1. चेतावनी implementor: इस कोड को एक ब्राउज़र में लिखे गए वर्णों
  2. चेतावनी ऑब्जर्वर: इस कोड की-वैल्यू के साथ अच्छी तरह से नहीं चलता है अवलोकन
  3. कैविट थ्रेडर: यह कोड बहुत धागा-सुरक्षित नहीं दिखता
  4. कैविट ARC'er: objc_allocateClassPair() एआरसी के साथ संकलित नहीं किया जा सकता है।
  5. कैविट डेवलपर: किसी ऑब्जेक्ट की कक्षा के साथ घूमना एक खतरनाक चीज है। इस तरह के वूडू के लिए पूरी तरह से वैध उपयोग हैं, लेकिन वे बहुत दुर्लभ हैं। अगर आपको लगता है कि आपको ऐसा करने की ज़रूरत है, तो आप शायद गलत हैं, और यहां एक नया प्रश्न पोस्ट करना चाहिए: "यही वह है जो मुझे लगता है कि मुझे करने की ज़रूरत है, क्या मैं?"
+1

यहां शामिल एक समय/अंतरिक्ष व्यापार भी है। यदि प्रत्येक उदाहरण विभिन्न तरीकों का समर्थन कर सकता है, तो रनटाइम में गतिशील कक्षाओं की संख्या कमजोर हो सकती है। इसके विपरीत, अगर वास्तव में केवल एक ही विधि है जिसमें कुछ हैं और कुछ नहीं करते हैं, तो विधि अग्रेषण में एक अस्वीकार्य गति लागत हो सकती है, और एक गतिशील उपclass बहुत तेज़ हो सकता है। –