2009-06-19 13 views
135

In MyClass.m, ho definitoObjective-C: La chiamata selettori con più argomenti

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

e la dichiarazione appropriato in MyClass.h. Più tardi voglio chiamare

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

in MyClass.m ma ottengo un errore simile al * Chiusura di applicazione a causa di eccezione non identificata 'NSInvalidArgumentException', la ragione: '* - [MyClass myTest: withAtring:]: selettore non riconosciuto inviato all'istanza 0xe421f0 '

Ho provato un caso più semplice con un selettore che non ha preso argomenti che hanno stampato una stringa in console e che ha funzionato bene. Cosa c'è di sbagliato nel codice e come posso risolverlo? Grazie.

+4

Il tuo post richiede "argomenti multipli", ma ne usi solo uno. Ora sono curioso di sapere come qualcuno lo farebbe con più argomenti, oltre a confezionarli in un array/dict/qualunque. – RonLugge

risposta

130

La tua firma metodo è:

- (void) myTest:(NSString *) 

withAString sembra essere il parametro (il nome è fuorviante, sembra che fa parte della firma del selettore).

Se si chiama la funzione in questo modo:

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

Funzionerà.

Ma, come gli altri utenti hanno suggerito, si consiglia di rinominare il metodo:

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

E non chiamate:

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

Grazie! Correzione minore. La "t" in "mytest:" dovrebbe essere in maiuscolo in "T". self performSelector: @selector (mytest :) withObject: myString]; – Stu

+0

Grazie, aggiornato il mio post :) –

+1

Ora che vedo che le persone hanno tratto beneficio da questa risposta, ho rivisto la mia risposta; Suggerirei che la chiamata sia semplicemente: - (void) testWithString: (NSString *) aString; –

2

pensano che la classe deve essere definita come:

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

avete solo un singolo parametro così si dovrebbe avere una sola:

Si potrebbe prendere in considerazione l'utilizzo% @ nel vostro NSLog anche - è solo una buona abitudine per entrare - scriverà quindi qualsiasi oggetto - non solo archi.

3

La firma del metodo non ha senso, sei sicuro che non sia un refuso? Non ho idea di come sia anche la compilazione, anche se forse ricevi degli avvertimenti che stai ignorando?

Quanti parametri si aspetta che questo metodo abbia?

+0

Mi spiace che tu stia scrivendo. Ho digitato e ho cercato di renderlo più semplice invece di copiare e incollare il mio codice, ma ho commesso un errore nel processo. Mi aspetto che questo metodo prenda un parametro; la stringa che vorrei stampare. – Stu

297

In Objective-C, la firma di un selettore costituito da:

  1. il nome del metodo (in questo caso sarebbe 'myTest') (richiesto)
  2. A ':' (due punti) che seguono il nome del metodo se il metodo ha un input.
  3. Un nome e ':' per ogni ulteriore input.

selettori hanno alcuna conoscenza di:

  1. I tipi di input
  2. tipo di ritorno del metodo.

Ecco un'implementazione della classe in cui il metodo performMethodsViaSelectors esegue gli altri metodi della classe per mezzo di selettori:

@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 

Il metodo che si desidera creare un selettore per ha un unico ingresso, quindi si dovrebbe creare un selettore per questo motivo:

SEL myTestSelector = @selector(myTest:); 
+3

Buona risposta. Per chiarire leggermente, il nome del selettore DEVE avere almeno una parte, che può o meno prendere un parametro - se lo fa, deve avere due punti. I nomi dei selettori con due o più parti DEVONO avere i due punti dopo CIASCUNA parte - non è legale avere un selettore del modulo "-useFoo: andBar: toDoSomething". –

+0

grazie per questo. Sono stato alle prese con questo per un po ', felice per l'aiuto! –

+0

in che modo i parametri di input sono numeri interi? cosa fare in questo caso? –

7

Il tuo codice ha due problemi. Uno è stato identificato e ha risposto, ma l'altro no. Il primo era che al tuo selettore mancava il nome del suo parametro. Tuttavia, anche quando lo aggiusti, la linea genera comunque un'eccezione, assumendo che la firma del metodo rivisto includa ancora più di un argomento. Diciamo che il vostro metodo riveduto è dichiarato come:

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

Creazione di selettori per metodi che accettano più argomenti è perfettamente valida (per esempio @selector (myTestWithString: comparedTo :)). Tuttavia, il metodo performSelector consente solo di passare un valore a myTest, che sfortunatamente ha più di un parametro. Errore e ti dirà che non hai fornito abbastanza valori.

Si può sempre ridefinire il metodo di prendere una collezione in quanto è unico parametro:

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

Tuttavia, v'è una soluzione più elegante (che non necessita di refactoring). La risposta è utilizzare NSInvocation, insieme ai suoi metodi setArgument:atIndex: e invoke.

Ho scritto an article, including a code example, se volete maggiori dettagli. L'attenzione è rivolta al threading, ma le nozioni di base si applicano ancora.

Buona fortuna!

13

@Shane Arney

performSelector:withObject:withObject: 

Si potrebbe anche voler dire che questo metodo è solo per il passaggio di un massimo di 2 argomenti, e non può essere ritardata. (Come ad esempio performSelector:withObject:afterDelay:)

un po 'strano che Apple supporta solo 2 oggetti da inviare e non ha ancora renderlo più generico

+2

Grazie per le informazioni. Non ho potuto ottenere il ritardo al lavoro e ora so perché. Per tua informazione, per aggirare il limite di due oggetti, ho passato un array e poi l'ho usato nel metodo. – JScarry

0

utenti iOS si aspettano anche autocapitalization:.. In un campo di testo standard, la prima lettera una frase in una lingua tra maiuscole e minuscole è automaticamente maiuscola

è possibile decidere se implementare tali caratteristiche;. non c'è API dedicato per nessuna delle caratteristiche appena elencate, in modo da fornire loro è un vantaggio competitivo .

Il documento Apple sta dicendo che non sono disponibili API per questa funzione e altre funzionalità previste in una tastiera personalizzata. quindi è necessario trovare la propria logica per implementare questo.