Come creare un NSArray (o NSMutableArray) di metodi di classe in Objective-C?


14

Sto provando a creare un NSArray di metodi in Objective-C.

(Quello che sto cercando di realizzare qui è qualcosa di simile al seguente in C)

devo porto questo a Objective-C e non so come costruire una serie di puntatori di funzione (in Objective-c world, metodi di classe ) in fase di compilazione.

In Objective-C ho il seguente.

- (void)handleCommandA { ... } 
- (void)handleCommandB { ... } 

/* Now how to add above 2 functions into NSArray? */ 
NSArray *handler_table = [NSArray arrayWithObjects:... ]; /* This doesn't seem to work. */ 
5

Utilizzare NSValue.

Ad esempio:

NSArray* handlers = [NSArray arrayWithObjects:[NSValue valueWithPointer:handleA] ... ]; 

poi per accedere a:

handleptr* handle = (handlerptr*)[[handlers objectAtIndex:0] pointerValue]; 
handle(foo_bar); 

28

Il problema qui è che per associare tali funzioni è necessario utilizzare la parola chiave selettore che restituisce un tipo SEL. Questo è un tipo di puntatore mentre NSArray memorizza oggetti.

Avete quindi tre opzioni;

  1. Utilizzare un normale C-tipo array
  2. piegare le funzioni in una classe derivata NSObject che li chiamerà.
  3. Utilizzare un protocollo.

Il secondo è probabilmente il più bello e per questo è possibile utilizzare la classe NSValue per contenere i risultati del selettore. Per esempio;

NSValue* selCommandA = [NSValue valueWithPointer:@selector(handleCommandA:)]; 
NSValue* selCommandB = [NSValue valueWithPointer:@selector(handleCommandB:)]; 

NSArray *handler_table = [NSArray arrayWithObjects:selCommandA, selCommandB, nil ]; 

Quando si è recuperata la voce corretta dall'array, per riconvertire si farebbe;

SEL mySelector = [selCommand pointerValue]; 
[someObject performSelector:mySelector]; 

(Nota sto supponendo che dalla sintassi Objective-C che questi sono destinati ad essere utilizzati come metodi su un oggetto e non funzioni globali. Se si desidera utilizzare globalmente allora li si dovrebbe scrivere come in chiaro C.)

Un'altra opzione è quella di formalizzare i metodi di comando in un protocollo. Ciò consente di scrivere funzionalità che funzioneranno su qualsiasi oggetto che implementa tale protocollo e il compilatore fornirà un controllo maggiore di quello che si avrebbe se si chiamassero solo selettori.

E.g.

// some header 
@protocol CommandHandler 
@required 
-(void) handleCommandA; 
-(void) handleCommandB; 
@end 

// some other header 
@interface someClass : NSObject<CommandHandler> 
{ 
// you will receive compiler warnings if you do not implement the protocol functions 
} 

Il codice di gestione e spedizione viene quindi scritto per funzionare con oggetti di tipo "CommandHandler". E.g

-(void) registerForCommands:(CommandHandler*)handler 
  0

preferisco usare le stringhe al posto di puntatori, in quanto renderebbe il debugging molto più facile. Guarda NSStringFromSelector() e NSSelectorFromString(). 17 mag. 092009-05-17 09:10:39

+1

Piccola correzione, utilizzando il selettore in realtà appare come: [someObject performSelector: mySelector]; 19 gen. 112011-01-19 03:30:33


4

In Objective-C, non si passano i metodi; si passa intorno ai selettori , che sono fondamentalmente i nomi canonici dei metodi. Quindi, per fare in modo che un oggetto risponda a un messaggio di selezione, inviarlo performSelector:. Per esempio:

NSString *exampleString = [NSString stringWithString:@"Hello"]; 
SEL methodName = @selector(stringByAppendingString:); 
    // ^This is the selector. Note that it just represents the name of a 
    // message, and doesn't specify any class or implementation 
NSString *combinedString = [exampleString performSelector:methodName withObject:@" world!"]; 

Che cosa si vorrà fare è quella di una serie di NSStrings contenenti i nomi dei selettori che ti interessa, è possibile utilizzare la funzione NSStringFromSelector() per fare questo.. Quindi, quando si desidera utilizzarli, chiamare NSSelectorFromString() sulle stringhe per richiamare il selettore originale e passarlo all'oggetto appropriato performSelector:.(Come mostrato nell'esempio sopra, il ricevitore non è codificato in un selettore - solo il nome del metodo - quindi potrebbe essere necessario memorizzare anche il ricevitore.)