2012-08-31 11 views
5

Mi código para registrar manejador de excepciones no detectadas usando UncaughtExceptionHandler es el siguiente, ¿cree que habrá algún problema potencial?Registre UncaughtExceptionHandler en Objective C usando NSSetUncaughtExceptionHandler

@interface AppDelegate() 

void myHandler(NSException * exception); 

@end 

@implementation AppDelegate 

void myHandler(NSException * exception) 
{ 
    // ... 
} 

- (BOOL) application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 
{ 
    NSSetUncaughtExceptionHandler(&myHandler); 
.. 

¿Es posible tener una forma más concisa de escribirlo?

Tengo que utilizar la extensión de clase para declarar prototipo con el fin de deshacerse de la advertencia de Sin prototipo previo para la función ..

Respuesta

10

de Martin es correcta. Sin embargo, pensé que elaboraría un poco, para explicar por qué es así.

La función de su definición:

void myHandler(NSException * exception) 
{ 
    // ... 
} 

define una función que será visible desde el exterior. En otras palabras (generalizadas, no técnicas), se creará un símbolo en el archivo objeto para que el vinculador pueda encontrarlo, lo que permite que otros archivos llamen al myHandler.

Sin embargo, como se supone que debe estar visible externamente, otros archivos tendrán que saber cómo se ve esa función. Ahí es donde el prototipo entra en juego. La advertencia es básicamente diciendo ...

Hey, que han declarado esta función para ser visible desde el exterior a otro código , pero no veo un prototipo que otro código se puede utilizar para saber acerca de la función.

Entonces, aparece una advertencia. Es una buena advertencia para tener. Le ayuda a recordar declarar prototipos para las funciones que desea exportar.

Ahora, como descubriste, puedes declarar un prototipo y la advertencia desaparece. Sin embargo, declarar el prototipo solo en el archivo de implementación debería ser otra advertencia para usted. Esa advertencia personal debería ser:

¿Realmente desea que esta función tenga visibilidad externa, o simplemente se llama en esta unidad de compilación? Si la función no va a tener visibilidad externa, entonces no hay necesidad de exportarla en la tabla de símbolos, y no hay necesidad de un prototipo que otros módulos puedan incluir para que conozcan la función.

En ese caso, se puede declarar la función static como en la respuesta de Martín:

static void myHandler(NSException * exception) 
{ 
    // ... 
} 

En este contexto, static le dice al compilador algo como:

Hey, compilador, crear código para esta función, y permite que cualquier código en esta unidad de compilación vea la función, pero no le dé visibilidad externa . No deseo que la función sea llamada por otros módulos.

En este caso, incluso si otro código declara el prototipo, no verían su función porque es "privada" para el archivo en el que está definida.

Dado que se está utilizando solo en el archivo local, no es necesario un prototipo, por lo que no es necesario que le advierta que no tiene uno.

Ahora, solo como una nota ... No necesita poner funciones C en las secciones @interface y @implementation de su código, ya que eso no hace nada. Esas funciones C se compilan con la misma visibilidad y acceso exactos, ya sea que estén dentro de las secciones ObjC o no.

Finalmente, si lo desea, puede deshabilitar esta advertencia en la configuración de compilación de Xcode (pero ahora que comprende el contexto de la advertencia, le sugiero que la deje activada).

+0

+1 Excelente explicación, como de costumbre. –

+1

Gracias por la explicación detallada, pero consulte mi problema, 'myHandler' se está registrando en' AppDelegate', pero la excepción no detectada puede ocurrir en cualquier clase, por lo que no estoy seguro si el uso de 'static' es correcto para mí. – Ryan

+2

@Yoga: Puedes usar 'static' aquí sin problema, porque pasas la dirección de' myHandler' a 'NSSetUncaughtExceptionHandler'. La visibilidad solo es importante para el enlazador. Si cualquier módulo tiene la dirección de 'myHandler', puede llamar a esta función independientemente de la visibilidad. - Pasar la dirección de una función estática local a otras funciones es un patrón común, p. para funciones de devolución de llamada, etc. –

0

Sí, esta es la forma correcta. Me pregunto por qué recibes la advertencia ya que tengo lo mismo sin declararlo en una categoría vacía y no aparece una advertencia ... Además, también puedes configurar manejadores de señal para capturar las señales SIGABRT, SIGILL y SIGBUS :

void signalHandler(int sig) { 

} 

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 
{ 
    struct sigaction newSignalAction; 
    memset(&newSignalAction, 0, sizeof(newSignalAction)); 
    newSignalAction.sa_handler = &signalHandler; 
    sigaction(SIGABRT, &newSignalAction, NULL); 
    sigaction(SIGILL, &newSignalAction, NULL); 
    sigaction(SIGBUS, &newSignalAction, NULL); 
    ... 
} 
+1

Apuesto a que tienes la advertencia desactivada en tu configuración de compilación. –

+0

Pff, sí, debo haberlo olvidado :) – graver

3

no te dan una advertencia sobre un prototipo que faltan si se declara la función como static: respuesta

static void myHandler(NSException * exception) 
{ 
    // ... 
} 
+0

+1 Correcto, como de costumbre. –