2011-01-06 57 views
19

Tengo problemas para seguir adelanteInvocación para trabajar. Por alguna razón, el tiempo de ejecución de Objective-C ignora por completo mi método forwardInvocation: y arroja una excepción de selector no reconocido.forwardInvocation no se llama?

Mi código de prueba es el siguiente:

@interface InvocationTest : NSObject 
{ 
} 

+ (void) runTest; 

@end 


@interface FullClass: NSObject 
{ 
    int value; 
} 
@property(readwrite,assign) int value; 

@end 

@implementation FullClass 

@synthesize value; 

@end 


@interface SparseClass: NSObject 
{ 
} 

@end 

@implementation SparseClass 

- (void)forwardInvocation:(NSInvocation *)forwardedInvocation 
{ 
    NSLog(@"ForawrdInvocation called"); 

    FullClass* proxy = [[[FullClass alloc] init] autorelease]; 
    proxy.value = 42; 
    [forwardedInvocation invokeWithTarget:proxy]; 
} 

@end 


@implementation InvocationTest 

+ (void) runTest 
{ 
    SparseClass* sparse = [[[SparseClass alloc] init] autorelease]; 
    NSLog(@"Value = %d", [sparse value]); 
} 

@end 

estoy trabajando fuera de la información de los siguientes recursos:

http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtForwarding.html#//apple_ref/doc/uid/TP40008048-CH105 http://cocoawithlove.com/2008/03/construct-nsinvocation-for-any-message.html

Por lo que yo puedo decir, el tiempo de ejecución debe invocar hacia adelanteInvocación: en la instancia de SparseClass cuando invoco [valor escaso], pero se ignora por completo:

- [valor SparseClass]: Selector no reconocido enviado a la instancia 0x4b1c4a0 *** Terminación de aplicación debido a excepción no detectada 'NSInvalidArgumentException', razón: '- [valor SparseClass]: Selector no reconocido enviado a la instancia 0x4b1c4a0'

Respuesta

36

También debe sobrescribir - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector para que funcione.

supongo

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector { 
    return [FullClass instanceMethodSignatureForSelector:aSelector]; 
} 

debería estar bien.

+1

¡Impresionante! Trabajado como un encanto. – Karl

24

De la documentación NSObject:

Importante: Para responder a los métodos que su objeto no reconoce en sí, debe invalidar methodSignatureForSelector: además de forwardInvocation:. El mecanismo para reenviar mensajes utiliza información obtenida de methodSignatureForSelector: para crear el objeto NSInvocation que se reenviará. Su método principal debe proporcionar una firma de método apropiada para el selector dado, ya sea preformulando uno o preguntando a otro objeto por uno.

Y, desde el runtime documentación:

... si un objeto reenvía los mensajes remotos que recibe, debe tener una versión de methodSignatureForSelector: que puede devolver descripciones precisas de los métodos que responden en última instancia, a los mensajes reenviados; por ejemplo, si un objeto es capaz de enviar un mensaje a su sustituto, que implementaría methodSignatureForSelector: de la siguiente manera:

- (NSMethodSignature*)methodSignatureForSelector:(SEL)selector 
{ 
    NSMethodSignature* signature = [super methodSignatureForSelector:selector]; 
    if (!signature) { 
     signature = [surrogate methodSignatureForSelector:selector]; 
    } 
    return signature; 
} 

Nota: Ver de answer para la correcta aplicación de methodSignatureForSelector: Jilouc.

+13

Creo que Apple's Runtime Programming Guide falla en este tema. En la sección "Reenvío", no mencionan nada sobre la necesidad de 'methodSignatureForSelector:' con 'forwardInvocation:'. Para encontrar ese tidbit, tiene que desplazarse 3 secciones hacia abajo para descubrir que necesita implementar un método de sección. – DBD