उद्देश्य-सी: कई तर्कों के साथ चयनकर्ताओं को कॉल करना


142

MyClass.m में, मैंने परिभाषित किया है

- (void) myTest: (NSString *) withAString{
    NSLog(@"hi, %@", withAString);
}

और MyClass.h में उपयुक्त घोषणा। बाद में मैं फोन करना चाहता हूं

[self performSelector:@selector(mytest:withAString:) withObject: mystring];

MyClass.m में। लेकिन मुझे एक अपवाद के रूप में एक त्रुटि मिलती है * अनकैप्ड अपवाद 'NSInvalidArgumentException' अपवाद के कारण ऐप को समाप्त करना, कारण: '* - [MyClass myTest: withAtring:]: unxcognized चयनकर्ता को 0xe421f0 पर भेजा गया'

मैंने एक चयनकर्ता के साथ एक सरल मामले की कोशिश की, जिसमें कोई तर्क नहीं था जो एक स्ट्रिंग को सांत्वना के लिए मुद्रित करता था और जो ठीक काम करता था। कोड में क्या गलत है और मैं इसे कैसे ठीक कर सकता हूं? धन्यवाद।


4
आपकी पोस्ट 'कई तर्कों' के बारे में पूछ रही है, लेकिन आप केवल एक का उपयोग करते हैं। अब मुझे इस बात की उत्सुकता है कि कोई व्यक्ति किसी तर्क / तानाशाही / जो भी हो, में लपेटने के अलावा कई तर्क के साथ क्या करता है।
RonLugge

जवाबों:


137

आपकी विधि हस्ताक्षर है:

- (void) myTest:(NSString *)

withAString पैरामीटर होता है (नाम भ्रामक है, ऐसा लगता है कि यह चयनकर्ता के हस्ताक्षर का हिस्सा है)।

यदि आप फ़ंक्शन को इस तरीके से कहते हैं:

[self performSelector:@selector(myTest:) withObject:myString];

यह काम करेगा।

लेकिन, जैसा कि अन्य पोस्टरों ने सुझाव दिया है, आप विधि का नाम बदलना चाह सकते हैं:

- (void)myTestWithAString:(NSString*)aString;

और कॉल करें:

[self performSelector:@selector(myTestWithAString:) withObject:myString];

2
अब जब मुझे लगता है कि लोगों को इस जवाब से लाभ हुआ है, मैंने अपनी प्रतिक्रिया की समीक्षा की है; मेरा सुझाव है कि कॉल बस हो: - (शून्य) testWithString: (NSString *) aString;
लिंडसे फर्ग्यूसन

313

ऑब्जेक्टिव-सी में, एक चयनकर्ता के हस्ताक्षर होते हैं:

  1. विधि का नाम (इस मामले में यह 'myTest' होगा) (आवश्यक)
  2. यदि विधि में एक इनपुट है तो विधि नाम के बाद एक ':' (कोलन)।
  3. हर अतिरिक्त इनपुट के लिए एक नाम और ':'।

चयनकर्ताओं को इसका कोई ज्ञान नहीं है:

  1. इनपुट प्रकार
  2. विधि का रिटर्न प्रकार।

यहाँ एक वर्ग कार्यान्वयन है जहाँ PerformMethodsViaSelectors विधि चयनकर्ताओं के माध्यम से अन्य वर्ग विधियों का प्रदर्शन करती है:

@implementation ClassForSelectors
- (void) fooNoInputs {
    NSLog(@"Does nothing");
}
- (void) fooOneIput:(NSString*) first {
    NSLog(@"Logs %@", first);
}
- (void) fooFirstInput:(NSString*) first secondInput:(NSString*) second {
    NSLog(@"Logs %@ then %@", first, second);
}
- (void) performMethodsViaSelectors {
    [self performSelector:@selector(fooNoInputs)];
    [self performSelector:@selector(fooOneInput:) withObject:@"first"];
    [self performSelector:@selector(fooFirstInput:secondInput:) withObject:@"first" withObject:@"second"];
}
@end

जिस विधि के लिए आप चयनकर्ता बनाना चाहते हैं, उसके पास एकल इनपुट है, इसलिए आप इसके लिए चयनकर्ता बनाएंगे:

SEL myTestSelector = @selector(myTest:);

3
अच्छा उत्तर। थोड़ा स्पष्ट करने के लिए, आपको चयनकर्ता नाम MUST में कम से कम एक भाग होना चाहिए, जो कोई पैरामीटर नहीं ले सकता है या नहीं - यदि यह करता है, तो इसके पास एक बृहदान्त्र होना चाहिए। दो या दो से अधिक भागों के साथ चयनकर्ता के नाम EACH भाग के बाद एक बृहदान्त्र होना चाहिए - यह "-useFoo: andBar: toDoSomething" के रूप का चयनकर्ता होना कानूनी नहीं है।
क्विन टेलर

इसके लिए धन्यवाद। ive कुछ समय के लिए इससे जूझ रहा था, मदद के लिए खुश!
जेम्स हॉल

कैसे इनपुट मापदंडों के बारे में पूर्णांक संख्या हैं? इस मामले में क्या करना है?
होआंग फाम

1
आपको एक NSNumber ऑब्जेक्ट में पूर्णांक को लपेटने की आवश्यकता होगी (देखें डेवलपर .apple.com/library/ios/#documentation/Cocoa/Reference/… ), और कॉल की गई विधि में पूर्णांक मान पुनः प्राप्त करें। यह थोड़ा वर्बोज़ हो सकता है (और मुझे इसके चारों ओर एक बेहतर तरीका नहीं मिला है) लेकिन यह ठीक काम करता है।
शेन आर्नी

30
+100: यह कमाल है! मैं कई "withObject:" मापदंडों का उपयोग करने में सक्षम होने के बारे में नहीं जानता था। अगर मैं कर सकता तो मैं इसे सौ गुना
बढ़ा देता

13

@ शाने अर्नी

performSelector:withObject:withObject:

आप यह भी उल्लेख करना चाहते हैं कि यह विधि केवल अधिकतम 2 तर्कों को पारित करने के लिए है, और इसमें देरी नहीं की जा सकती है। (जैसे performSelector:withObject:afterDelay:)

थोड़े अजीब कि सेब केवल 2 वस्तुओं को भेजने के लिए समर्थन करता है और इसे और अधिक सामान्य नहीं बनाता है।


2
जानकारी के लिए धन्यवाद। मुझे काम करने में देरी नहीं हुई और अब मुझे पता है कि क्यों। FYI करें, दो वस्तुओं की सीमा पाने के लिए, मैंने एक सरणी पास की और फिर इसका उपयोग विधि में किया।
जेस्कार्री

7

आपके कोड में दो समस्याएं हैं। एक की पहचान की गई और जवाब दिया गया, लेकिन दूसरा नहीं था। पहला यह था कि आपके चयनकर्ता को इसके पैरामीटर का नाम याद नहीं था। हालाँकि, जब आप इसे ठीक करते हैं, तब भी लाइन एक अपवाद को बढ़ा देगी, यह मानते हुए कि आपके संशोधित विधि हस्ताक्षर में अभी भी एक से अधिक तर्क शामिल हैं। मान लें कि आपकी संशोधित विधि इस प्रकार घोषित की गई है:

-(void)myTestWithString:(NSString *)sourceString comparedTo:(NSString *)testString ;

कई तर्कों को लेने वाले तरीकों के लिए चयनकर्ता पूरी तरह से वैध हैं (जैसे @selector (myTestWithString: तुलनाTT :))। हालाँकि, performSelector विधि केवल आपको myTest में एक मान पास करने की अनुमति देती है, जो दुर्भाग्य से एक से अधिक पैरामीटर है। यह त्रुटि करेगा और आपको बताएगा कि आपने पर्याप्त मानों की आपूर्ति नहीं की है।

आप हमेशा अपने संग्रह को फिर से परिभाषित कर सकते हैं क्योंकि यह केवल एक पैरामीटर है:

-(void)myTestWithObjects:(NSDictionary *)testObjects ;

हालांकि, एक और अधिक सुंदर समाधान है (जिसमें रिफैक्टिंग की आवश्यकता नहीं है)। इसका उत्तर NSInvocation का उपयोग करना है, साथ ही इसके setArgument:atIndex:और invokeतरीके।

यदि आप अधिक विवरण चाहते हैं, तो मैंने एक कोड उदाहरण सहित एक लेख लिखा है । फोकस थ्रेडिंग पर है, लेकिन मूल बातें अभी भी लागू होती हैं।

सौभाग्य!


3

आपके विधि हस्ताक्षर से कोई मतलब नहीं है, क्या आपको यकीन है कि यह टाइपो नहीं है? मुझे यह स्पष्ट नहीं है कि यह कैसे संकलित हो रहा है, हालांकि शायद आपको चेतावनी मिल रही है जिसे आप अनदेखा कर रहे हैं?

इस पद्धति को लेने के लिए आप कितने मापदंडों की अपेक्षा करते हैं?


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

2

लगता है कि कक्षा को इस प्रकार परिभाषित किया जाना चाहिए:

- (void) myTestWithSomeString:(NSString *) astring{
    NSLog(@"hi, %s", astring);
}

आपके पास केवल एक ही पैरामीटर है, इसलिए आपको केवल एक एकल होना चाहिए:

आप अपने NSLog में% @ का उपयोग करने पर भी विचार कर सकते हैं - यह सिर्फ एक अच्छी आदत है - तब किसी भी वस्तु को लिखेंगे - न कि केवल तार।


-1

iOS उपयोगकर्ता भी स्वतः पूर्णता की अपेक्षा करते हैं: एक मानक पाठ क्षेत्र में, केस-संवेदी भाषा में वाक्य का पहला अक्षर स्वचालित रूप से पूंजीकृत होता है।

आप तय कर सकते हैं कि ऐसी सुविधाओं को लागू करना है या नहीं; अभी सूचीबद्ध किसी भी सुविधा के लिए कोई समर्पित एपीआई नहीं है, इसलिए उन्हें प्रदान करना एक प्रतिस्पर्धात्मक लाभ है।

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

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.