Cambiando un método con argumentos variables y reenviando el mensaje - Acceso incorrecto

Estoy implementando una "Clase de inyector de código", que a través del método swizzling puede darle la posibilidad de hacer algo como esto:

FLCodeInjector *injector = [FLCodeInjector injectorForClass:[self class]];
[injector injectCodeBeforeSelector:@selector(aSelector:) code:^{
    NSLog(@"This code should be injected");
}];

aSelector puede ser un método con número variable de argumentos y tipo de retorno variable. Los argumentos / y el tipo de retorno pueden ser objetos o tipo primitivo.

En primer lugar, adjunto el código deinjectCodeBeforeSelector: para que entiendas lo que estoy haciendo (eliminé partes no interesantes del código):

- (void)injectCodeBeforeSelector:(SEL)method code:(void (^)())completionBlock
{

    NSString *selector = NSStringFromSelector(method);

    [self.dictionaryOfBlocks setObject:completionBlock forKey:selector];

    NSString *swizzleSelector = [NSString stringWithFormat:@"SWZ%@", selector];

    // add a new method to the swizzled class
    Method origMethod = class_getInstanceMethod(self.mainClass, NSSelectorFromString(selector));
    const char *encoding = method_getTypeEncoding(origMethod);

    [self addSelector:NSSelectorFromString(swizzleSelector) toClass:self.mainClass methodTypeEncoding:encoding];
    SwizzleMe(self.mainClass, NSSelectorFromString(selector), NSSelectorFromString(swizzleSelector));

}

-(void)addSelector:(SEL)selector toClass:(Class)aClass methodTypeEncoding:(const char *)encoding
{
    class_addMethod(aClass,
                    selector,
                    (IMP)genericFunction, encoding);
}

Básicamente, utilizo class_addMethod para agregar el método falso / swizzle a la clase de destino, luego hago el swizzle. La implementación del método se establece en una función como esta:

id genericFunction(id self, SEL cmd, ...) {
    // call the block to inject
    ...
    // now forward the message to the right method, since method are swizzled
    // I need to forward to the "fake" selector SWZxxx

    NSString *actualSelector = NSStringFromSelector(cmd);
    NSString *newSelector = [NSString stringWithFormat:@"SWZ%@", actualSelector];
    SEL finalSelector = NSSelectorFromString(newSelector);

    // forward the argument list
    va_list arguments;
    va_start ( arguments, cmd );

    return objc_msgSend(self, finalSelector, arguments);
}

Ahora el problema: tengo un EXC_BAD_INSTRUCTION (objc_msgSend_corrupt_cache_error ()) en la última línea. El problema pasa si reenvío los argumentos va_listal selector falso. Si cambio la última línea a

return objc_msgSend(self, cmd, arguments);

No hay error, pero obviamente comienza una recursión infinita.

He intentado:

usar va_copyelimina el swizzle antes de enviar el mensaje

pero no hay resultados. Creo que el problema está relacionado con este hecho: va_list no es un puntero simple, puede ser algo similar a un desplazamiento relativo a la dirección de pila del método. Por lo tanto, no puedo llamar a objc_msgsend de una función (la función swizzled) con la lista arg de otra función (la que no está swizzled).

Intenté cambiar el enfoque y copiar todos los argumentos en una NSInvocation, pero tuve otros problemas para administrar el valor de retorno de la invocación, e incluso copiar los argumentos uno por uno (administrar todos los tipos diferentes) requiere mucho código, por lo que preferí devolverlos. Para este enfoque, eso me parece más limpio (imho).

¿Tienes alguna sugerencia? Gracias

Respuestas a la pregunta(2)

Su respuesta a la pregunta