iOS - कई तर्कों और afterDelay के साथ एक परफॉर्मर कैसे लागू करें?


90

मैं एक iOS नौसिखिया हूँ। मेरे पास चयनकर्ता विधि इस प्रकार है -

- (void) fooFirstInput:(NSString*) first secondInput:(NSString*) second
{

}

मैं कुछ इस तरह से लागू करने की कोशिश कर रहा हूं -

[self performSelector:@selector(fooFirstInput:secondInput:) withObject:@"first" withObject:@"second" afterDelay:15.0];

लेकिन यह कहना मुझे एक त्रुटि देता है -

Instance method -performSelector:withObject:withObject:afterDelay: not found

क्या मैं याद कर रहा हूँ के रूप में किसी भी विचार?

जवाबों:


142

व्यक्तिगत रूप से, मुझे लगता है कि आपकी आवश्यकताओं का एक निकट समाधान NSInvocation का उपयोग है।

निम्नलिखित की तरह कुछ काम करेंगे:

indexPath और डेटा स्रोत दो उदाहरण एक ही विधि में परिभाषित चर हैं।

SEL aSelector = NSSelectorFromString(@"dropDownSelectedRow:withDataSource:");

if([dropDownDelegate respondsToSelector:aSelector]) {
    NSInvocation *inv = [NSInvocation invocationWithMethodSignature:[dropDownDelegate methodSignatureForSelector:aSelector]];
    [inv setSelector:aSelector];
    [inv setTarget:dropDownDelegate];

    [inv setArgument:&(indexPath) atIndex:2]; //arguments 0 and 1 are self and _cmd respectively, automatically set by NSInvocation
    [inv setArgument:&(dataSource) atIndex:3]; //arguments 0 and 1 are self and _cmd respectively, automatically set by NSInvocation

    [inv invoke];
}

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

यह एक महान समाधान की तरह दिखता है। क्या इस तकनीक से आह्वान की जाने वाली विधि से रिटर्न वैल्यू प्राप्त करने का कोई तरीका है?
डेविड पेटीग्रेव

15
आप इस तकनीक के साथ देरी को कैसे निर्दिष्ट करते हैं?
मृत्यु_

4
@death_au, इसके बजाय invoke, कॉल करें: [inv performSelector:@selector(invoke) withObject:nil afterDelay:1]; मुझे सहमत होना चाहिए कि यह एक महान समाधान है। सभी को मुबारक!
मैक्सिम चेतृस्का

2
बातचीत के लिए देर से, लेकिन एक सवाल है। ड्रॉपडाउनडेलगेट क्या है?
मिनिस्ट्रोन-सूप

98

क्योंकि [NSObject performSelector:withObject:withObject:afterDelay:]विधि जैसी कोई चीज नहीं है ।

आपको उस डेटा को एनकैप्सुलेट करना होगा जिसे आप किसी एकल ऑब्जेक्ट सी ऑब्जेक्ट (जैसे एक NSArray, एक NSDictionary, कुछ कस्टम ऑब्जेक्टिव C टाइप) में भेजना चाहते हैं और फिर इसे उस [NSObject performSelector:withObject:afterDelay:]विधि से पास करें जिसे अच्छी तरह से जाना जाता है और प्यार करता है।

उदाहरण के लिए:

NSArray * arrayOfThingsIWantToPassAlong = 
    [NSArray arrayWithObjects: @"first", @"second", nil];

[self performSelector:@selector(fooFirstInput:) 
           withObject:arrayOfThingsIWantToPassAlong  
           afterDelay:15.0];

यदि मुझे afterDelay param को हटाने में कोई त्रुटि नहीं आती है क्या इसका मतलब यह है कि afterDelay को एक से अधिक परम के साथ उपयोग करने की अनुमति नहीं है?
सुचि

1
आपको कोई त्रुटि नहीं मिलती है, लेकिन मैं शर्त लगा सकता हूं कि आपको रन टाइम के दौरान एक "चयनकर्ता नहीं मिला" अपवाद मिलेगा (और जिस चीज़ को आप करने की कोशिश कर रहे हैं उसे कॉल नहीं किया जाएगा) ... यह कोशिश करें और देखें। :-)
माइकल डाऊटरमैन

मैं यहां बूल टाइप कैसे पास करूं?
विराट

इसे एक ऑब्जेक्टिव C स्टाइल ऑब्जेक्ट बनाएं (उदाहरण के लिए " NSNumber * whatToDoNumber = [NSNumber numberWithBool: doThis];") और इसे एक पैरामीटर, @virata के रूप में पास करें।
माइकल डुटर्मन 25

2
यह एक अलग सवाल है @ राज ... कृपया इसे अलग से पोस्ट करें।
माइकल ड्यूटर्मन 25

34

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

एक अन्य विकल्प डिस्पैच_ आफ्टर है, जो एक ब्लॉक लेगा और एक निश्चित समय में इसे एनक्यू करेगा।

double delayInSeconds = 15.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);

dispatch_after(popTime, dispatch_get_main_queue(), ^(void){

    [self fooFirstInput:first secondInput:second];

});

या, जैसा कि आप पहले ही खोज चुके हैं, यदि आपको देरी की आवश्यकता नहीं है तो आप इसका उपयोग कर सकते हैं - performSelector:withObject:withObject:


इस दृष्टिकोण के बारे में भी अच्छा है कि आप __weakअपने प्री-टाइमर को केवल स्वयं के लिए एक कमजोर लिंक देने के लिए उपयोग कर सकते हैं - इसलिए आप कृत्रिम रूप से अपनी वस्तु के जीवनचक्र को बढ़ा नहीं पाते हैं और जैसे यदि आपका प्रदर्शनकर्ता: afterDelay: पूंछ की तरह थोड़ा प्रभाव डालता है पुनरावृत्ति (पुनरावृत्ति के बिना यद्यपि) तो यह बनाए रखने के चक्र को हल करता है।
टॉमी

1
हाँ यह स्वीकृत उत्तर होना चाहिए। इसका अधिक उपयुक्त और सीधा आगे।
रूहुल

7

सबसे आसान विकल्प आपके विधि को संशोधित करने के रूप में इस तरह के एक दोनों बहस, जिसमें एक एकल पैरामीटर लेने के लिए है NSArrayया NSDictionary(या एक दूसरी विधि है कि एक एकल पैरामीटर लेता है, यह unpacks, और पहली विधि कॉल जोड़ें और फिर फोन दूसरा एक पर विधि देरी)।

उदाहरण के लिए, आपके पास कुछ ऐसा हो सकता है:

- (void) fooOneInput:(NSDictionary*) params {
    NSString* param1 = [params objectForKey:@"firstParam"];
    NSString* param2 = [params objectForKey:@"secondParam"];
    [self fooFirstInput:param1 secondInput:param2];
}

और फिर इसे कॉल करने के लिए, आप कर सकते हैं:

[self performSelector:@selector(fooOneInput:) 
      withObject:[NSDictionary dictionaryWithObjectsAndKeys: @"first", @"firstParam", @"second", @"secondParam", nil] 
      afterDelay:15.0];

क्या होगा अगर विधि को संशोधित नहीं किया जा सकता है, यह कहें कि यह UIKit में रहता है या कुछ और? इतना ही नहीं, NSDictionaryलॉज़ टाइप करने के लिए विधि को बदलने के साथ-साथ सुरक्षा भी। आदर्श नहीं।
फतुहोकू

@fatuhoku - यह पार्थिव द्वारा कवर किया गया है; "एक दूसरी विधि जोड़ें जो एकल पैरामीटर लेता है, उसे अनपैक करता है, और पहली विधि कहता है"। यह परवाह किए बिना कि पहली विधि कहाँ रहती है। प्रकार की सुरक्षा के लिए, उस पल को खो दिया गया था जब निर्णय का उपयोग किया गया था performSelector:(या NSInvocation)। अगर यह चिंता का विषय है, तो संभवतः सबसे अच्छा विकल्प जीसीडी के माध्यम से जाना होगा।
अरोथ

6
- (void) callFooWithArray: (NSArray *) inputArray
{
    [self fooFirstInput: [inputArray objectAtIndex:0] secondInput: [inputArray objectAtIndex:1]];
}


- (void) fooFirstInput:(NSString*) first secondInput:(NSString*) second
{

}

और इसके साथ कॉल करें:

[self performSelector:@selector(callFooWithArray) withObject:[NSArray arrayWithObjects:@"first", @"second", nil] afterDelay:15.0];

5

आप प्रदान किए गए प्रदर्शन के सभी प्रकार पा सकते हैं: यहां दिए गए तरीके:

http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/nsobject_Class/Reference/Reference.html

विविधताओं का एक समूह है, लेकिन एक ऐसा संस्करण नहीं है जो कई वस्तुओं के साथ-साथ देरी भी करता है। आपको इसके बजाय NSArray या NSDictionary में अपने तर्क को लपेटने की आवश्यकता होगी।

- performSelector:
- performSelector:withObject:
- performSelector:withObject:withObject:
 performSelector:withObject:afterDelay:
 performSelector:withObject:afterDelay:inModes:
 performSelectorOnMainThread:withObject:waitUntilDone:
 performSelectorOnMainThread:withObject:waitUntilDone:modes:
 performSelector:onThread:withObject:waitUntilDone:
 performSelector:onThread:withObject:waitUntilDone:modes:
 performSelectorInBackground:withObject: 

2

मुझे NSInvocation तरीका बहुत जटिल लगता है। आइए इसे सरल और साफ रखें:

// Assume we have these variables
id target, SEL aSelector, id parameter1, id parameter2;

// Get the method IMP, method is a function pointer here.
id (*method)(id, SEL, id, id) = (void *)[target methodForSelector:aSelector];

// IMP is just a C function, so we can call it directly.
id returnValue = method(target, aSelector, parameter1, parameter2);

अच्छा! 'Vc' को 'लक्ष्य' से बदलें
एंटोन

1

मैंने अभी-अभी कुछ स्विज़ किया और मूल विधि को कॉल करने की आवश्यकता थी। मैंने जो किया वह एक प्रोटोकॉल बना रहा था और मैंने अपनी वस्तु को उसमें डाल दिया। एक अन्य तरीका एक श्रेणी में विधि को परिभाषित करना है, लेकिन एक चेतावनी के दमन की आवश्यकता होगी (#pragma clang diagnostic "-Wincomplete-कार्यान्वयन")।


0

विस्तार NSObjectऔर कार्यान्वित करने का एक सरल और पुन: प्रयोज्य तरीका है

- (void)performSelector:(SEL)aSelector withObjects:(NSArray *)arguments;

कुछ इस तरह:

- (void)performSelector:(SEL)aSelector withObjects:(NSArray *)arguments
{
    NSMethodSignature *signature = [self methodSignatureForSelector: aSelector];
    NSInvocation *invocation = [NSInvocation invocationWithMethodSignature: signature];
    [invocation setSelector: aSelector];

    int index = 2; //0 and 1 reserved
    for (NSObject *argument in arguments) {
        [invocation setArgument: &argument atIndex: index];
        index ++;
    }
    [invocation invokeWithTarget: self];
}

0

मैं बस अपने सभी मापदंडों को गुणों के रूप में रखते हुए एक कस्टम ऑब्जेक्ट बनाऊंगा, और फिर उस एकल ऑब्जेक्ट को पैरामीटर के रूप में उपयोग करूंगा

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