का उपयोग करते हुए -performSelector: बनाम सिर्फ विधि बुला


116

मैं अभी भी ऑब्जेक्टिव-सी के लिए नया हूं और मैं सोच रहा हूं कि निम्नलिखित दो कथनों में क्या अंतर है?

[object performSelector:@selector(doSomething)]; 

[object doSomething];

जवाबों:


191

मूल रूप से performSelector आपको गतिशील रूप से यह निर्धारित करने की अनुमति देता है कि चयनकर्ता किस ऑब्जेक्ट पर दिए गए चयनकर्ता को कॉल करे। दूसरे शब्दों में चयनकर्ता को रनटाइम से पहले निर्धारित नहीं किया जाना चाहिए।

इस प्रकार भले ही ये समतुल्य हों:

[anObject aMethod]; 
[anObject performSelector:@selector(aMethod)]; 

दूसरा रूप आपको ऐसा करने की अनुमति देता है:

SEL aSelector = findTheAppropriateSelectorForTheCurrentSituation();
[anObject performSelector: aSelector];

इससे पहले कि आप संदेश भेजें।


3
यह इंगित करने के लायक है कि आप वास्तव में aSelector के लिए खोज के लिए उपयुक्त TheAppAppselectorForTheCurrentSituation () का परिणाम निर्दिष्ट करेंगे, फिर आह्वान करें [anObject performSelector: aSelector]। @selector एक SEL का निर्माण करता है।
डैनियल यांकोव्स्की

4
का उपयोग करते हुए performSelector:कुछ आप शायद ही अगर आप अपने वर्ग में लक्ष्य कार्रवाई को लागू करना है। भाई बहन performSelectorInBackground:withObject:और performSelectorOnMainThread:withObject:waitUntilDone:अक्सर अधिक उपयोगी होते हैं। बैकग्राउंड थ्रेड को स्पैनिंग के लिए, और बैकग्राउंड थ्रेड से मुख्य थ्रेड पर कॉल करने के लिए।
PeyloW

2
performSelectorसंकलित चेतावनियों को दबाने के लिए भी उपयोगी है। यदि आप जानते हैं कि विधि मौजूद है (जैसे उपयोग करने के बाद respondsToSelector), तो यह Xcode को यह कहने से रोक देगा कि "जवाब नहीं दे सकता है your_selector"। चेतावनी के वास्तविक कारण का पता लगाने के बजाय इसका उपयोग न करें । ;)
मार्क

मैंने StackOverflow पर कुछ अन्य थ्रेड पर पढ़ा कि PerformSelector का उपयोग एक भयानक डिजाइन का प्रतिबिंब था, और इसमें कई अंगूठे थे। काश मैं इसे फिर से पा पाता। मैंने Google को खोजा, परिणाम को स्टैकओवरफ़्लो तक सीमित कर दिया, और 18,000 परिणाम प्राप्त किए। Eww।
लोगिक्सॉरस रेक्स

"एक भयानक डिजाइन का प्रतिबिंब" अत्यधिक सरलीकृत है। ब्लॉक उपलब्ध होने से पहले हमारे पास यही था, और सभी उपयोग खराब नहीं हैं, तब या अब। हालांकि अब है कि ब्लॉक कर रहे हैं उपलब्ध है, कि शायद नए कोड जब तक आप बहुत ही सरल कुछ कर रहे हैं के लिए एक बेहतर विकल्प है।
ईथन

16

प्रश्न में इस मूल उदाहरण के लिए,

[object doSomething];
[object performSelector:@selector(doSomething)]; 

जो होने वाला है, उसमें कोई अंतर नहीं है। doSomething वस्तु द्वारा सिंक्रोनाइज़ की जाएगी। केवल "doSomething" एक बहुत ही सरल विधि है, जो कुछ भी वापस नहीं करता है, और किसी भी पैरामीटर की आवश्यकता नहीं है।

क्या यह कुछ अधिक जटिल था, जैसे:

(void)doSomethingWithMyAge:(NSUInteger)age;

चीजें जटिल हो जाएंगी, क्योंकि [वस्तु doSomethingWithMyAge: 42];

अब "performSelector" के किसी भी संस्करण के साथ नहीं बुलाया जा सकता है, क्योंकि मापदंडों वाले सभी संस्करण केवल ऑब्जेक्ट पैरामीटर स्वीकार करते हैं।

चयनकर्ता यहाँ "doSomethingWithMyAge:" होगा, लेकिन किसी भी प्रयास के लिए

[object performSelector:@selector(doSomethingWithMyAge:) withObject:42];  

बस संकलन नहीं होगा। एक NSNumber पास करना: 42 के बजाय @ (42), या तो मदद नहीं करेगा, क्योंकि विधि एक बुनियादी सी प्रकार की उम्मीद करती है - एक वस्तु नहीं।

इसके अलावा, प्रदर्शन पैरामीटर 2 पैरामीटर तक हैं, कोई अधिक नहीं। जबकि कई बार तरीकों में कई और पैरामीटर होते हैं।

मुझे पता चला है कि हालांकि प्रदर्शन के तुल्यकालिक वेरिएंट:

- (id)performSelector:(SEL)aSelector;
- (id)performSelector:(SEL)aSelector withObject:(id)object;
- (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;

हमेशा एक वस्तु वापस करें, मैं एक साधारण BOOL या NSUInteger भी वापस करने में सक्षम था, और यह काम किया।

PerformSelector के दो मुख्य उपयोगों में से एक गतिशील रूप से उस विधि का नाम लिखना है जिसे आप निष्पादित करना चाहते हैं, जैसा कि पिछले उत्तर में बताया गया है। उदाहरण के लिए

 SEL method = NSSelectorFromString([NSString stringWithFormat:@"doSomethingWithMy%@:", @"Age");
[object performSelector:method];

अन्य उपयोग, अतुल्यकालिक रूप से एक संदेश को वस्तु के लिए भेजना है, जिसे बाद में वर्तमान रनअप पर निष्पादित किया जाएगा। इसके लिए, कई अन्य परफॉर्मर वेरिएंट हैं।

- (void)performSelector:(SEL)aSelector withObject:(id)anArgument afterDelay:(NSTimeInterval)delay inModes:(NSArray *)modes;
- (void)performSelector:(SEL)aSelector withObject:(id)anArgument afterDelay:(NSTimeInterval)delay;
- (void)performSelector:(SEL)aSelector target:(id)target argument:(id)arg order:(NSUInteger)order modes:(NSArray *)modes;
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait modes:(NSArray *)array;
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait;
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait modes:(NSArray *)array;
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait;
- (void)performSelectorInBackground:(SEL)aSelector withObject:(id)arg;

(हाँ, मैंने उन्हें कई फाउंडेशन क्लास श्रेणियों से इकट्ठा किया, जैसे NSThread, NSRunLoop और NSObject)

प्रत्येक संस्करण का अपना विशेष व्यवहार होता है, लेकिन सभी कुछ साझा करते हैं (कम से कम जब waUntilDone NO पर सेट होता है)। "PerformSelector" कॉल तुरंत वापस आ जाएगी, और ऑब्जेक्ट पर संदेश केवल कुछ समय बाद चालू रनलूप पर रखा जाएगा।

विलंबित निष्पादन के कारण - स्वाभाविक रूप से कोई वापसी मूल्य उपलब्ध नहीं है, चयनकर्ता की विधि है, इसलिए - (शून्य) इन सभी अतुल्यकालिक वेरिएंट में वापसी मूल्य।

मुझे उम्मीद है कि मैंने इसे किसी तरह कवर किया ...


12

@ennuikiller पर हाजिर है। मूल रूप से, गतिशील रूप से उत्पन्न चयनकर्ता आपके लिए उपयोगी होते हैं जब आप (और आमतौर पर संभवतः नहीं कर सकते हैं) उस विधि का नाम जानते हैं जिसे आप कोड संकलित करते समय कॉल करेंगे।

एक महत्वपूर्ण अंतर यह है कि -performSelector:दोस्त और ( बहु-थ्रेडेड और विलंबित वेरिएंट सहित ) कुछ हद तक सीमित हैं कि वे 0-2 मापदंडों वाले तरीकों के साथ उपयोग के लिए डिज़ाइन किए गए हैं। उदाहरण के लिए, -outlineView:toolTipForCell:rect:tableColumn:item:mouseLocation:6 मापदंडों के साथ कॉल करना और वापस लौटना NSStringबहुत कठिन है, और प्रदान की गई विधियों द्वारा समर्थित नहीं है।


5
ऐसा करने के लिए, आपको एक NSInvocationवस्तु का उपयोग करना होगा ।
डेव डोंग सोंग

6
एक और अंतर: performSelector:और दोस्त सभी ऑब्जेक्ट तर्क लेते हैं, जिसका अर्थ है कि आप उन्हें कॉल नहीं कर सकते हैं (उदाहरण के लिए) setAlphaValue:, क्योंकि इसका तर्क एक फ्लोट है।
चक

4

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

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


5
चयनकर्ता वास्तव में एक फ़ंक्शन पॉइंटर की तरह बिल्कुल भी नहीं हैं जिसमें एक फ़ंक्शन पॉइंटर ऐसा कुछ है जिसे आप तर्कों के साथ कह सकते हैं और एक चयनकर्ता का उपयोग किसी भी ऑब्जेक्ट पर किसी विशेष विधि को कॉल करने के लिए किया जा सकता है जो इसे लागू करता है; एक चयनकर्ता के पास फ़ंक्शन पॉइंटर की तरह मंगलाचरण का पूरा संदर्भ नहीं होता है।
bbum

1
चयनकर्ता फ़ंक्शन पॉइंटर्स के समान नहीं हैं, लेकिन मुझे अभी भी लगता है कि वे समान हैं। वे क्रियाओं का प्रतिनिधित्व करते हैं। C फंक्शन पॉइंटर्स क्रियाओं का भी प्रतिनिधित्व करते हैं। अतिरिक्त संदर्भ के बिना न तो उपयोगी है। चयनकर्ताओं को एक वस्तु और मापदंडों की आवश्यकता होती है; फंक्शन पॉइंटर्स के लिए पैरामीटर की आवश्यकता होती है (जिसमें किसी ऑब्जेक्ट को ऑपरेट करना शामिल हो सकता है)। मेरा कहना यह था कि वे NSInvocation वस्तुओं से कैसे अलग हैं, जिसमें सभी आवश्यक संदर्भ हैं। शायद मेरी तुलना भ्रामक थी, जिस मामले में मैं माफी मांगता हूं।
डैनियल यांकोव्स्की

1
चयनकर्ता फ़ंक्शन पॉइंटर्स नहीं हैं। आस - पास भी नहीं। वे वास्तविकता में सरल सी स्ट्रिंग हैं, जिसमें एक विधि का "नाम" होता है (जैसा कि 'फ़ंक्शन' के विपरीत)। वे विधि हस्ताक्षर भी नहीं कर रहे हैं, क्योंकि वे मापदंडों के प्रकारों को एम्बेड नहीं करते हैं। ऑब्जेक्ट में एक ही चयनकर्ता के लिए एक से अधिक विधि हो सकती है (विभिन्न प्रकार के परम, या अलग-अलग रिटर्न प्रकार)।
मोति श्नोर 12

-7

दोनों के बीच एक और सूक्ष्म अंतर है।

    [object doSomething]; // is executed right away

    [object performSelector:@selector(doSomething)]; // gets executed at the next runloop

यहाँ Apple प्रलेखन से अंश है

"performSelector: withObject: afterDelay: अगले रन लूप चक्र के दौरान और एक वैकल्पिक विलंब अवधि के दौरान वर्तमान थ्रेड पर निर्दिष्ट चयनकर्ता निष्पादित करता है। क्योंकि यह चयनकर्ता को निष्पादित करने के लिए अगले रन लूप चक्र तक इंतजार करता है, ये विधियाँ स्वत: मिनी विलंब प्रदान करती हैं। वर्तमान में क्रियान्वित कोड। कई कतारबद्ध चयनकर्ताओं को एक क्रम में एक के बाद एक प्रदर्शन किया जाता है। "


1
आपका उत्तर तथ्यात्मक रूप से गलत है। आपके द्वारा उद्धृत प्रलेखन के बारे में है performSelector:withObject:afterDelay:, लेकिन सवाल और आपके स्निपेट का उपयोग कर रहे हैं performSelector:, जो एक पूरी तरह से अलग विधि है। इसके लिए डॉक्स से: <उद्धरण> performSelector:विधि aSelectorसीधे रिसीवर को संदेश भेजने के बराबर है । </ उद्धरण>
jscs

3
स्पष्टीकरण के लिए धन्यवाद जोश। तुम सही हो; मुझे लगा कि performSelector/performSelector:withObject/performSelector:withObject:afterDelayसभी ने उसी तरह का व्यवहार किया है जो एक गलती थी।
avi
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.