2012-05-11 12 views
5

Así que básicamente estoy implementando la forma típica de manejar llamadas de JavaScript en objc usando window.location = "myobj: mymethod: myarg: myotherarg", sin embargo, me pregunto si hay una manera de aplicar una matriz de argumentos a un método, similar a cómo puedes hacerlo en JavaScript.¿Hay JavaScript como método de aplicación en Objective-C?

Normalmente he estado haciendo

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

preferiría hacer:

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

y tener un método como este:

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

es esto posible?

Respuesta

2

Si sabe que ningún método tomará más de dos argumentos, puede usar performSelector:withObject:withObject: para hacer estas llamadas. Si el método toma menos de dos argumentos, los campos no utilizados withObject: serán ignorados.

+ (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]; 
} 

Si no puede haber más de dos argumentos, se tiene que utilizar NSInvocation. Esta clase le permite construir un mensaje al pasar los diversos argumentos y definir el selector y el objeto, luego enviar el mensaje y obtener el resultado.

+ (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í ... pero el punto es ser capaz de aplicar un conjunto dinámico de argumentos a un método, de la misma manera que la función JS apply, para crear un puente muy limpio entre las llamadas a la función WebView JS al objetivo nativo- C métodos. Así que, básicamente, podría tener otra clase de Objective-C llamada JSFunctionMethods, que duplicaría la API de las llamadas JS en mi API de JS que implemento en mi webview. Gracias por su aporte, y espero haber aclarado mejor. –

+0

@Jesse Acabo de publicar eso mientras recuerdo cómo usar 'NSInvocation'.Ver mi adición (o la respuesta de @ Andrew). – ughoavgfhw

+0

¡Oh, esto es increíble! ¡Gracias! –

2

No estoy seguro de que entiendo completamente la pregunta (no conozco bien el JavaScript). Sin embargo, puede usar NSInvocation para enviar mensajes arbitrarios a cualquier objeto. Algo como esto:

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

Gracias Andrew ... esto es exactamente lo que necesitaba. –

1

Es posible que desee buscar NSInvocation. Específicamente, desea construir una Invocación NS con la firma de método del selectorName (NSObject-methodResignatureForSelector :), luego establecer el selector, el destino y los argumentos. Tenga en cuenta: debe verificar los tipos de argumentos (NSMethodSignature -getArgumentTypeAtIndex :, es igual a '@'), y los argumentos que está pasando se indexan empezando por 2 (porque 0 y 1 son el objeto y el selector de métodos))

No estoy diciendo que esto sea una buena idea, por cierto; hay muy pocos casos donde se justifica este enfoque.

+0

Creo que para mis usos encaja bien. ¡Muchas gracias! –

0

Es un poco torpe, pero es posible:

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

Convencionalmente arg1 habría una cadena que define los tipos de datos y número de parámetros adicionales.

Usted lo llamaría así:

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

Su método de matriz es probablemente más claro para la mayoría de los propósitos.

+0

Ah sí ... esto es lo que trato de evitar ... Básicamente estoy buscando una API duplicada en mi código js y objc, con algún método que vincule la traducción. Gracias. –

+0

Pensó que preferiría el método NSInvocation, pero, igualmente, pensó que valía la pena demostrar que había otra forma de hacerlo. (Si agrega un contenedor, esto es prácticamente lo mismo solo en C que en Objective-C). –

Cuestiones relacionadas