मैं गतिशील रूप से ऑब्जेक्टिव-सी के साथ रनटाइम पर चयनकर्ता कैसे बना सकता हूं?


93

मुझे पता है कि एक SELसंकलन समय का उपयोग करके कैसे बनाया जाए , @selector(MyMethodName:)लेकिन मैं जो करना चाहता हूं वह एक से गतिशील रूप से चयनकर्ता बनाना है NSString। क्या यह भी संभव है?

मैं क्या कर सकता हूँ:

SEL selector = @selector(doWork:);
[myobj respondsToSelector:selector];

मैं क्या करना चाहता हूँ: (छद्म कोड, यह स्पष्ट रूप से काम नहीं करता है)

SEL selector = selectorFromString(@"doWork");
[myobj respondsToSelector:selector];

मैं Apple API डॉक्स खोज रहा हूं, लेकिन ऐसा कोई तरीका नहीं मिला है जो कंपाइल-टाइम @selector(myTarget:)सिंटैक्स पर निर्भर न हो ।

जवाबों:


180

मैं एक ऑब्जेक्टिव-सी प्रोग्रामर नहीं हूं, केवल एक हमदर्द हूं , लेकिन शायद NSSelectorFromString वह है जो आपको चाहिए। यह रनटाइम संदर्भ में अन्वेषण का उल्लेख है कि आप इसे स्ट्रिंग को चयनकर्ता में बदलने के लिए उपयोग कर सकते हैं।


5
मुझे अपने Google-fu पर ब्रश करने की आवश्यकता है। ठीक वही है जो मैं देख रहा था (या जैसा था वैसा नहीं हो सकता)।
क्रेग

ठीक है, मैं अभी भी अपने बुकमार्क में चारों ओर उड़ान लिंक था क्योंकि मैंने कुछ दिनों पहले ऑब्जेक्टिव-सी 2.0 डॉक्स के माध्यम से पढ़ा है।
टॉर्स्टन मारेक

40

XCode प्रलेखन के अनुसार, आपका psuedocode मूल रूप से सही हो जाता है।

यह मानों को असाइन करने के लिए सबसे कुशल है @ संकलनकर्ता () निर्देश के साथ संकलित समय पर सेलेक्ट चर। हालाँकि, कुछ मामलों में, एक प्रोग्राम को रनवे पर एक चरित्र स्ट्रिंग को चयनकर्ता में बदलने की आवश्यकता हो सकती है। यह NSSelectorFromString फ़ंक्शन के साथ किया जा सकता है:

setWidthHeight = NSSelectorFromString(aBuffer);

संपादित करें: बुमेर, बहुत धीमा। : पी


2
NSStringFromSelector(@"doWork")इसे दूसरे तरीके से परिवर्तित करता है (सिर्फ
फी

8
मुझे लगता है कि आपका मतलब है, NSStringFromSelector (@selector (doWork))
jpswain

और क्या है कि चयनकर्ता माना जाता है? क्या हमें कोई ब्लॉक या कुछ निर्दिष्ट नहीं करना चाहिए?
1149 बजे user4951

12

मुझे यह कहना होगा कि यह पिछले उत्तरदाताओं के उत्तरों की तुलना में थोड़ा अधिक जटिल है ... यदि आप वास्तव में चयनकर्ता बनाना चाहते हैं ... तो केवल "कॉल एक" न करें जिसे आपने "चारों ओर" रखा है। ।

आपको एक फ़ंक्शन पॉइंटर बनाने की आवश्यकता है जिसे आपके "नए" तरीके से कॉल किया जाएगा। इसलिए एक विधि के लिए [self theMethod:(id)methodArg];, जैसे आप लिखेंगे ...

void (^impBlock)(id,id) = ^(id _self, id methodArg) { 
     [_self doSomethingWith:methodArg]; 
};

और फिर आपको IMPब्लॉक को गतिशील रूप से उत्पन्न करने की आवश्यकता है , इस बार, पासिंग, "स्व" SEL,, और कोई भी तर्क ...

void(*impFunct)(id, SEL, id) = (void*) imp_implementationWithBlock(impBlock);

और इसे अपने वर्ग में जोड़ें, पूरे चूसने वाले के लिए एक सटीक विधि हस्ताक्षर के साथ (इस मामले में "v@:@", शून्य रिटर्न, ऑब्जेक्ट कॉलर, ऑब्जेक्ट तर्क)

 class_addMethod(self.class, @selector(theMethod:), (IMP)impFunct, "v@:@");

आप इस तरह के रनटाइम शनीगन्स के कुछ अच्छे उदाहरण देख सकते हैं , मेरे एक रेपो में, यहाँ।


5

मुझे पता है कि यह बहुत पहले से उत्तर दिया गया है, लेकिन फिर भी मैं साझा करना चाहता हूं। यह sel_registerNameभी उपयोग किया जा सकता है ।

प्रश्न में उदाहरण कोड को इस तरह से फिर से लिखा जा सकता है:

SEL selector = sel_registerName("doWork:");
[myobj respondsToSelector:selector];

2
दरअसल, NSSelectorFromString@ टॉर्स्ट-मर्क का उल्लेख sel_registerNameहूड के तहत किया जाता है। appledev : "NSSelectorFromString एक UTF-8 एनकोडेड कैरेक्टर रिप्रेजेंटेशन का aSelectorName को sel_registerName पास करता है और उस फंक्शन द्वारा लौटाए गए मान को वापस लौटाता है"
PLG
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.