2009-05-31 8 views
51

Per il metodo:Come passare @selector come parametro?

[NSThread detachNewThreadSelector:@selector(method:) toTarget:self withObject:(id)SELECTOR]; 

Come faccio a passare in un @selector? Ho provato a lanciarlo su (id) per farlo compilare, ma si blocca in runtime.


Più in particolare, ho un metodo come questo:

+(void)method1:(SEL)selector{ 
[NSThread detachNewThreadSelector:@selector(method2:) toTarget:self withObject:selector]; 
} 

Si blocca. Come faccio a passare nel selettore senza crash, in modo che il nuovo thread possa chiamare il selettore quando il thread è pronto?

risposta

67

Il problema qui non sta passando un selettore a un metodo, di per sé, ma passando un selettore in cui è previsto un oggetto. Per passare un valore non oggetto come oggetto, è possibile utilizzare NSValue. In questo caso, dovrai creare un metodo che accetti un NSValue e recuperi il selettore appropriato. Ecco un esempio di implementazione:

@implementation Thing 
- (void)method:(SEL)selector { 
    // Do something 
} 

- (void)methodWithSelectorValue:(NSValue *)value { 
    SEL selector; 

    // Guard against buffer overflow 
    if (strcmp([value objCType], @encode(SEL)) == 0) { 
     [value getValue:&selector]; 
     [self method:selector]; 
    } 
} 

- (void)otherMethodShownInYourExample { 
    SEL selector = @selector(something); 
    NSValue *selectorAsValue = [NSValue valueWithBytes:&selector objCType:@encode(SEL)]; 
    [NSThread detachNewThreadSelector:@selector(methodWithSelectorValue:) toTarget:self withObject:selectorAsValue]; 
} 
@end 
+0

+50 Eccellente! Non riesco mai a ricordare come farlo ... – bentford

+0

Perché devi fare quel bit con il nuovo thread? – cstack

+2

@cstack: se guardi la domanda, generare un nuovo thread è ciò che l'OP stava cercando di fare. Quindi ho usato lo stesso compito nel mio esempio. Ma questa tecnica non è in alcun modo specifica per generare un nuovo thread. – Chuck

0

Se non si desidera specificare un oggetto basta usare nullo.

[NSThread detachNewThreadSelector:@selector(method:) toTarget:self withObject:nil]; 

Se è necessario passare un oggetto al selettore sarebbe simile a questa.

Qui sto passando una stringa al metodo "setText".

NSString *string = @"hello world!"; 
[NSThread detachNewThreadSelector:@selector(setText:) toTarget:self withObject:string]; 


-(void)setText:(NSString *)string { 
    [UITextField setText:string]; 
} 
+0

si prega di consultare le domande aggiornate. Grazie! – erotsppa

4

Uso NSValue, in questo modo:

+(void)method1:(SEL)selector { 
    NSValue *selectorValue = [NSValue value:&selector withObjCType:@encode(SEL)]; 
    [NSThread detachNewThreadSelector:@selector(method2:) 
          toTarget:self 
          withObject:selectorValue]; 
} 

NSValue è inteso come un oggetto-involucro per i tipi non oggetto arbitrario.

+0

Credo che manchi un segno "&" prima del "selettore" in modo che finisca per essere "... value: & selector ..." invece di "... value: selector ...". – Senseful

+0

Vero. Grazie per aver notato; L'ho risolto –

41

È possibile convertire tra selettori e oggetti stringa utilizzando le funzioni NSStringFromSelector() e NSSelectorFromString(). Quindi puoi semplicemente passare gli oggetti stringa.

In alternativa, se non si desidera modificare i metodi, è possibile creare uno NSInvocation per creare una chiamata per la chiamata al metodo (poiché può impostare le chiamate con argomenti non di oggetto), quindi chiamarla [NSThread detachNewThreadSelector:@selector(invoke) toTarget:myInvocation withObject:nil];

+0

Questo ha bisogno di più upvotes –

+0

Questa è la migliore risposta del lotto, vorrei poter avere più persone a prevalere su questo. –

+0

Mille grazie, questo era proprio quello di cui avevo bisogno. – amergin