2012-06-08 10 views
7

Este código me da EXC_BAD_ACCESS, ¿por qué?por qué este código da EXC_BAD_ACCESS (usando IMP)

NSMutableDictionary *d = [[NSMutableDictionary alloc] init]; 
IMP imp= [d methodForSelector:@selector(setObject:forKey:) ]; 
imp(d, @selector(setObject:forKey:), @"obj", @"key"); 

Estoy empezando a usar IMP, primero intento ... sin suerte. No estoy seguro de por qué recibo el error, también .. en el pasado, cuando recibí EXC_BAD_ACCESS, el mensaje se imprimió en la consola, esta vez la línea de error está resaltada.

Algunas notas: ARC está activado, XCode 4.3.2, el proyecto utiliza Objective-C++ como lenguaje de defecto/compilador, este código está en el inicio del proyecto

gracias chicos

+0

No puedo reproducir. Si pones esto en un proyecto nuevo, ¿sigues recibiendo el error? – Chuck

+0

Sí, lo que he encontrado ... ARC es el problema. Intenta crear un nuevo proyecto de iOS con ARC habilitado. Luego copie y pegue el código en alguna parte (lo puse en la aplicación didFinishLaunchingWithOptions :) – subzero

Respuesta

20

Necesita lanzar el puntero a la función correctamente o ARC no sabe lo que se supone que debe hacer. IMP es un puntero de función genérico que toma un id, un selector y un número variable de otros argumentos indefinidos y devuelve un id. La implementación del método que está tratando de llamar toma una identificación, un selector seguido de exactamente dos parámetros de identificación y tiene un tipo de devolución anómala. Lo puede solucionar cambiando al siguiente código:

NSMutableDictionary* dict = [[NSMutableDictionary alloc] init]; 
void (*imp)(id, SEL, id, id) = (void(*)(id,SEL,id,id))[dict methodForSelector:@selector(setObject:forKey:)]; 
if(imp) imp(dict, @selector(setObject:forKey:), @"obj", @"key"); 

Siempre debe comprobar que en realidad tiene un puntero de función antes de volver deferenciarlo, ya que también se estrellaría. El código anterior funcionará incluso en un entorno ARC. Además, incluso cuando no esté utilizando ARC, siempre debe enviar sus punteros a la función del prototipo real en lugar de IMP. Nunca debes usar IMP. Otros lugares que causarían problemas importantes son si el método devuelve una estructura o si el método toma parámetros de coma flotante, etc.

Buen hábito: siempre envíe los punteros a su función o haga typedefs para ellos si encuentra la sintaxis del puntero función discordante .

+0

Gracias Jason. Funcionó como un encanto !. Pregunta: ¿por qué causaría un problema importante con estructuras o métodos con parámetros de coma flotante? Si pudiera indicarme algún documento, sería más feliz. Acabo de encontrar el tema "tiempo de ejecución" interesante. – subzero

+1

Tiene que ver con las convenciones de llamada de funciones en C y cómo se pasan los parámetros. Como el compilador no sabe nada sobre los parámetros de IMP después de los parámetros 'self' y' _cmd', simplemente insertará otros parámetros en la pila y esperará que la función llamada sepa qué hacer con ellos. Sin embargo, si la función llamada espera un flotante, casi con certeza se verá en el GPR (para ARM) u otro registro específico de fp y no en la pila, etc. Lo mismo ocurre con los tipos de devolución, las estructuras se manejan de forma diferente que los punteros. –

1

El problema es que IMP tiene un tipo de devolución de "id" que ARC intentará administrar. Necesita convertir su puntero de función para tener un tipo de nulo de retorno (coherente con el método al que está llamando):

NSMutableDictionary *d = [[NSMutableDictionary alloc] init]; 
    IMP imp= [d methodForSelector: @selector(setObject:forKey:)]; 
    void (*func)(__strong id,SEL,...) = (void (*)(__strong id, SEL, ...))imp; 
    func(d, @selector(setObject:forKey:), @"obj", @"key"); 
+0

'void (*) (id, SEL, ...)' no es el tipo correcto para el puntero de función. Es 'void (*) (id, SEL, id, id)'. Aunque puede funcionar en este caso particular en ciertas arquitecturas con ciertos tipos ('id'), es incorrecto en general. – newacct

+0

Esto realmente funcionó. Gracias. – Felipe

Cuestiones relacionadas