2009-08-28 16 views
35

Esiste un modo che io possa passare gli argomenti in selettore?Argomenti a @selector

esempio: Ho questo metodo

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

} 

e devo chiamare questa funzione tramite un selettore passando due argomenti.

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

Come posso fare questo?

risposta

56

È potrebbe utilizzare il metodo NSTimer:

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

Invece, dal momento che un oggetto NSInvocation vi permetterà di passare argomenti; un oggetto NSInvocation è, come docs definiscono:

un Objective-C messaggio reso statico, cioè, si tratta di un'azione trasformato in un oggetto.

Mentre creazione di un oggetto NSTimer utilizzando un selettore richiede il formato del metodo essere:

- (void)timerFireMethod:(NSTimer*)theTimer 

Un NSInvocation consente di impostare la destinazione, il selettore, e gli argomenti che vengono passati in:

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]; 

Dove MyObject è la classe che viene dichiarata myMethod:setValue2: e attuate sulla - instanceMethodSignatureForSelector: è un functi convenienza on dichiarato su NSObject che restituisce per te un oggetto NSMethodSignature da passare a NSInvocation.

Inoltre, da notare, con setArgument:atIndex:, gli indici di argomenti da passare al metodo impostare come inizio selettore all'indice 2. Dalla documentazione:

indici 0 e 1 indicano gli argomenti nascosti auto e _cmd, rispettivamente; dovresti impostare questi valori direttamente con setTarget: e setSelector: metodi.Utilizzare gli indici 2 e maggiori per gli argomenti normalmente passati in un messaggio.

+1

Questa è una risposta migliore della mia. Dovresti farlo per evitare di inquinare le tue implementazioni con metodi non necessari. –

+3

Si noti che, se 'str1' e' str2' non sono stati assegnati in modo statico, si perderebbero loro. 'NSTimer' è documentato come l'invio di' -retainArguments' al suo oggetto di invocazione, ma non sarebbe male per voi di inviare '-retainArguments' all'oggetto di invocazione da soli. Il problema è mantenere gli argomenti da soli, quindi dire l'invocazione per mantenerli, pure. Non conservare autonomamente gli argomenti di chiamata! Lascia che l'invocazione lo gestisca - e, qui, lascia che il timer lo gestisca da solo. –

+3

Non hardcode la classe di 'targetInstance', come è stato fatto nel recuperare la firma del metodo. Se si volesse veramente usare '+ instanceMethodSignatureForSelector:', si potrebbe usare '[[classe targetInstance instanceMethodSignatureForSelector: selector]', ma inutilmente complesso - basta chiedere all'oggetto stesso la firma del metodo usando '[targetInstance methodSignatureForSelector: selector]' . –

-2
@selector(myMethod:setValue2:) 

Dal momento che il selettore per il metodo non è solo chiamato myMethod ma invece myMethod:setValue2:.

Anche (e potrei essere fuori base qui), credo che tecnicamente si possano eliminare le parole tra due punti e quindi utilizzare anche @selector(myMethod::) ma non citatemi su questo a meno che altri possano confermarlo.

+2

Che non è corretto. Il selettore è l'intero nome del metodo, compreso tutto tra i due punti. 'myMethod ::' e 'myMethod: setValue2:' sono selettori distinti, che verrebbero associati a implementazioni distinte a meno che non si sia lavorato a un po 'di magia di runtime. –

+0

OK. Ero fuori base. – jbrennan

27

Per il scheduledTimerWithTimeInterval:, il selettore che si passa può avere solo un argomento. Inoltre, il suo argomento deve essere un oggetto NSTimer *. In altre parole, il selettore deve assumere la seguente forma:

- (void)timerFireMethod:(NSTimer*)theTimer 

Che cosa si potrebbe fare è memorizzare gli argomenti nel dizionario userInfo e chiamare il selettore che si desidera dal callback del timer:

- (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

Questo è corretto per il metodo specifico che hai postato sopra isiaatz. Se questo è solo un esempio e vuoi sapere in generale come inviare più argomenti a un selettore, modifica la tua domanda – h4xxr

+0

Mi piace questa risposta migliore della risposta accettata poiché è più concisa. –

+1

Preferisco anche questo meglio –

2

Sembra un posto di lavoro per i blocchi (supponendo che questo è mirato per Snow Leopard.)

-jcr

0

blocchi sembrare una risposta ovvia ora ... Ma c'è un altro linguaggio che è stato molto comune nella fase di esecuzione classica, salamoia tuoi argomenti in un unico oggetto:

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

} 

ora è possibile inviare a

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