2012-05-11 11 views
5

Quindi in pratica sto implementando il modo tipico di gestire le chiamate JavaScript in objc usando window.location = "myobj: mymethod: myarg: myotherarg", tuttavia, mi chiedo se c'è un modo per applicare una serie di argomenti a un metodo, simile a come è possibile in JavaScript.È possibile applicare JavaScript come metodo nell'obiettivo-c?

In genere ho fatto

-(void) mymethod:(NSArray*) arr{ 
    //method knows how many arguments it takes and what they mean at each index 
} 

preferirei fare:

-(void) mymethod:(NSString*) myarg myOtherArg: (NSString*) myotherarg{ 
    //do stuff 
} 

e hanno un metodo come questo:

+(void) callMethod:(NSString*)selectorName withArgs: (NSArray*)args onObject:(id) obj{ 
    //implementation 
} 
[JEHelpers callMethod:selector withArgs:someArrayOfArgs onObject:myapp] 

è possibile?

risposta

2

Se si sa che nessun metodo richiede più di due argomenti, è possibile utilizzare performSelector:withObject:withObject: per effettuare queste chiamate. Se il metodo richiede meno di due argomenti, i campi non utilizzati withObject: verranno ignorati.

+ (id)callMethod:(NSString *)selectorName withArgs:(NSArray *)args onObject:(id)obj { 
    id arg1 = nil, arg2 = nil; 
    if([args count]) { 
     arg1 = [args objectAtIndex:0]; 
     if([args count] > 1]) 
      arg2 = [args objectAtIndex:1]; 
    } 
    return [obj performSelector:NSSelectorFromString(selectorName) 
        withObject:arg1 withObject:arg2]; 
} 

Se ci potrebbero essere più di due argomenti, si dovrà usare NSInvocation. Questa classe ti consente di costruire un messaggio passando i vari argomenti e definendo il selettore e l'oggetto, quindi invia il messaggio e ottieni il risultato.

+ (id)callMethod:(NSString *)selectorName withArgs:(NSArray *)args onObject:(id)obj { 
    SEL sel = NSSelectorFromString(selectorName); 
    NSMethodSignature *signature = [obj methodSignatureForSelector:sel]; 
    NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature]; 
    [invocation setSelector:sel]; 
    [invocation setTarget:obj]; 
    NSUInteger index = 2; 
    for(id arg in args) { 
     [invocation setArgument:&arg atIndex:index]; 
     ++index; 
    } 
    id result; 
    [invocation setReturnValue:&result]; 
    [invocation invoke]; 
    return result; 
} 
+0

Sì ... ma il punto è essere in grado di applicare un insieme dinamico di argomenti a un metodo, allo stesso modo della funzione JS apply, per creare un ponte molto pulito tra le chiamate della funzione JS di WebView all'Obiettivo nativo- Metodi C Quindi fondamentalmente potrei avere un'altra classe Objective-C chiamata JSFunctionMethods, che rispecchierebbe l'API delle chiamate JS nella mia API JS che implemento nella mia webview. Grazie per il tuo contributo, e spero di aver chiarito meglio. –

+0

@Jesse L'ho appena postato mentre ricordo come usare 'NSInvocation'.Vedi la mia aggiunta (o la risposta di @ Andrew). – ughoavgfhw

+0

Oh, è fantastico! Grazie! –

2

Non sono sicuro di comprendere completamente la domanda (non conosco bene JavaScript). Tuttavia, è possibile utilizzare NSInvocation per inviare messaggi arbitrari a qualsiasi oggetto. Qualcosa del genere:

+(void) callMethod:(NSString*)selectorName withArgs: (NSArray*)args onObject:(id) obj 
{ 
    SEL selector = NSSelectorFromString(selectorName); 
    if (![obj respondsToSelector:selector]) { 
     // Object doesn't respond to selector, so do something else/handle the error 
    } 
    NSMethodSignature *methodSignature = [obj methodSignatureForSelector:selector]; 
    NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSignature]; 
    [invocation setTarget:obj]; 
    [invocation setSelector:selector]; 
    for (NSUInteger i=0; i<[args count]; i++) { 
     id argument = [args objectAtIndex:i]; 
     [invocation setArgument:&argument atIndex:i+2]; // Arg 0 is self, arg 1 is _cmd 
    } 
    id result; 
    [invocation setReturnValue:&result]; 
    [invocation invoke]; 
} 
+0

Grazie Andrew ... questo è esattamente quello di cui avevo bisogno. –

1

Si potrebbe voler esaminare NSInvocazione. In particolare, si desidera creare un NSInvocation con il selettore del metodo di selectorName (NSObject -methodSignatureForSelector :), quindi impostare il selettore, il target e gli argomenti. Ricordati: dovresti controllare i tipi di argomento (NSMethodSignature -getArgumentTypeAtIndex :, è uguale a '@'), e gli argomenti che stai passando sono indicizzati a partire da 2 (perché 0 e 1 sono il sé dell'oggetto e il selettore del metodo).

Non sto dicendo che questa è una buona idea, btw; ci sono molto pochi casi in cui questo approccio è giustificato.

+0

Penso che per i miei usi si adatta bene. Molte grazie! –

0

È un po 'maldestro ma è possibile:

- (id)method:(NSString *)arg1, ... { 
    va_list args; 
    va_start(args, arg1); 
    for (NSString *a = arg1; a!= nil; a= va_arg(args, NSString*)) { 
    // do stuff 
    } 
} 

Convenzionalmente arg1 sarebbe una stringa che definisce i tipi di dati e il numero di parametri aggiuntivi.

si definirebbe così:

[self method:@"5", @"4", @"3", @"2", @"1"]; 

Il tuo metodo array è probabilmente più chiaro per la maggior parte degli scopi.

+0

Ah si ... questo è quello che sto cercando di evitare ... Sto fondamentalmente cercando un'API specchiata nel mio codice js e objc, con un metodo che collega la traduzione. Grazie. –

+0

Pensavo che preferiresti il ​​metodo NSInvocation, ma, allo stesso modo, ho pensato che valesse la pena dimostrare che c'era un altro modo per farlo. (Se aggiungi un wrapper, questo è praticamente lo stesso solo in C piuttosto che in Objective-C.) –

Problemi correlati