2009-08-28 6 views
35

Gibt es eine Möglichkeit, Argumente im Selektor übergeben?Argumente in @selector

Beispiel: Ich habe diese Methode

- (void)myMethod:(NSString*)value1 setValue2:(NSString*)value2{ 

} 

und ich brauche diese Funktion durch einen Selektor nennen zwei Argumente.

[NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(/*my method*/) userInfo:nil repeats:YES]; 

Wie kann ich das tun?

Antwort

56

Sie verwenden Sie die NSTimer Methode könnte:

+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)seconds 
           invocation:(NSInvocation *)invocation 
            repeats:(BOOL)repeats; 

Stattdessen da ein NSInvocation Objekt ermöglicht es Ihnen, Argumente zu übergeben; ein NSInvocation Objekt ist, wie der es docs definieren:

ein Objective-C-Nachricht gerenderte statisch, das heißt, es ist eine Aktion in ein Objekt eingeschaltet.

während ein NSTimer Objekt erstellt einen Selektor erfordert das Format des Verfahrens infrage kommen:

- (void)timerFireMethod:(NSTimer*)theTimer 

Ein NSInvocation ermöglicht, das Ziel gesetzt, den Wähler und die Argumente, die in übergeben:

SEL selector = @selector(myMethod:setValue2:); 

NSMethodSignature *signature = [MyObject instanceMethodSignatureForSelector:selector]; 
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature]; 
[invocation setSelector:selector]; 

NSString *str1 = @"someString"; 
NSString *str2 = @"someOtherString"; 

//The invocation object must retain its arguments 
[str1 retain]; 
[str2 retain]; 

//Set the arguments 
[invocation setTarget:targetInstance]; 
[invocation setArgument:&str1 atIndex:2]; 
[invocation setArgument:&str2 atIndex:3]; 

[NSTimer scheduledTimerWithTimeInterval:0.1 invocation:invocation repeats:YES]; 

Wo MyObject die Klasse ist, dass myMethod:setValue2: deklariert und implementiert auf - instanceMethodSignatureForSelector: ist eine Bequemlichkeit functi auf deklariert auf NSObject, die ein NSMethodSignature Objekt für Sie zurückgibt, an NSInvocation übergeben werden.

Auch zu beachten, mit setArgument:atIndex:, der Indizes für Argumente an der als Wähler Start 2. Aus der docs am Index gesetzt Methode übergeben werden:

Indizes 0 und 1 zeigt die versteckten Argumente Selbst und _cmd jeweils; Sie sollten diese Werte direkt mit den Methoden setTarget: und setSelector: festlegen.Verwenden Sie Indizes 2 und höher für die Argumente, die normalerweise in einer Nachricht übergeben werden.

+1

Das ist eine bessere Antwort als meine. Sie sollten dies tun, um zu vermeiden, dass Ihre Implementierungen mit unnötigen Methoden verschmutzt werden. –

+3

Beachten Sie, dass, wenn 'str1' und' str2' nicht statisch zugewiesen sind, Sie sie verlieren würden. 'NSTimer' ist so dokumentiert, dass '-retainArguments' an sein Aufrufobjekt gesendet wird, aber es würde nicht schaden, wenn Sie' -retainArguments' selbst an das Aufrufobjekt senden. Das Problem besteht darin, die Argumente selbst beizubehalten und dann dem Aufruf zu sagen, sie zu behalten. Behalten Sie die Aufrufargumente nicht selbst! Lassen Sie die Invokation damit umgehen - und lassen Sie den Timer selbst damit umgehen. –

+3

Die Klasse von 'targetInstance' nicht hart codieren, wie beim Abrufen der Methodensignatur. Wenn Sie '+ instanceMethodSignatureForSelector:' wirklich verwenden möchten, können Sie '[[targetInstance class] instanceMethodSignatureForSelector: selector]' verwenden, aber das ist unnötig komplex - fragen Sie das Objekt selbst nach der Methodensignatur mit '[targetInstance methodSignatureForSelector: selector]' . –

-2
@selector(myMethod:setValue2:) 

Da der Wähler für Ihre Methode nur myMethod wird nicht aufgerufen, sondern myMethod:setValue2:.

Auch (und ich könnte hier Basis sein), glaube ich technisch können Sie die Wörter zwischen Doppelpunkten fallen und damit auch @selector(myMethod::) verwenden, aber zitieren Sie mich nicht auf diese, es sei denn andere können es bestätigen.

+2

Das ist falsch. Der Selektor ist der vollständige Name der Methode, einschließlich alles zwischen den Doppelpunkten. 'myMethod ::' und 'myMethod: setValue2:' sind eindeutige Selektoren, die mit verschiedenen Implementierungen verknüpft sind, sofern Sie nicht mit Laufzeitzauber gearbeitet haben. –

+0

OK. Ich war außerhalb der Basis. – jbrennan

27

Für scheduledTimerWithTimeInterval: kann der Selektor, den Sie übergeben, nur ein Argument haben. Des Weiteren muss das eine Argument ein NSTimer * Objekt sein. Mit anderen Worten muss der Wähler die folgende Form:

- (void)timerFireMethod:(NSTimer*)theTimer 

Was Sie tun können, die Argumente in dem userInfo Wörterbuch ist zu speichern und rufen Sie die Wahl Sie aus dem Timer-Rückruf will:

- (void)startMyTimer { 
    /* ... Some stuff ... */ 
    [NSTimer scheduledTimerWithTimeInterval:0.1 
            target:self 
            selector:@selector(callMyMethod:) 
            userInfo:[NSDictionary dictionaryWithObjectsAndKeys:someValue, 
         @"value1", someOtherValue, @"value2", nil] 
            repeats:YES]; 
} 

- (void)callMyMethod:(NSTimer *)theTimer { 
    NSString *value1 = [[theTimer userInfo] objectForKey:@"value1"]; 
    NSString *value2 = [[theTimer userInfo] objectForKey:@"value2"]; 
    [self myMethod:value1 setValue2:value2]; 
} 
+2

Dies ist korrekt für die spezifische Methode, die Sie über Isiaatz geschrieben haben. Wenn das nur ein Beispiel wäre und Sie im Allgemeinen wissen möchten, wie man mehrere Argumente an einen Selektor sendet, ändern Sie bitte Ihre Frage – h4xxr

+0

Ich mag das besser als die angenommene Antwort, da es prägnanter ist. –

+1

Ich bevorzuge dies auch besser –

2

Sieht aus wie ein Job für die Blöcke (diese Annahme für Snow Leopard ausgerichtet ist.)

-jcr

0

Blöcke wie eine offensichtliche Antwort scheint jetzt ... aber es ist eine andere Idiom, das sehr war alltäglich in der klassischen Laufzeit, Ihre Argumente in einem einzelnen Objekt Beize:

- (void)doMyMethod:(NSDictionary *)userInfo 
{ 
    [self myMethod: [userInfo objectForKey:@"value1"] setValue2: [userInfo objectForKey:@"value2"]]; 
} 
- (void)myMethod:(NSString*)value1 setValue2:(NSString*)value2{ 

} 

jetzt können Sie auf

Versand
[self performSelector:@selector(doMyMethod:) withObject:@{@"value1":@"value1",@"value2":@"value2"}];