Registre UncaughtExceptionHandler en Objective C usando NSSetUncaughtExceptionHandler

4 minutos de lectura

Mi código para registrar el controlador de excepciones no detectado usando UncaughtExceptionHandler es el siguiente, ¿crees que habrá algún problema potencial?

@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?

Necesito usar la extensión de clase para declarar prototipo para deshacerme de la advertencia de No hay prototipo previo para la función ..

La respuesta de Martín es correcta. Sin embargo, pensé en elaborar un poco, para explicar por qué es así.

Su definición de función:

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

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

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

Oye, has declarado que esta función es visible externamente para otro código, pero no veo un prototipo que otro código pueda usar para conocer la función.

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

Ahora, como descubrió, puede 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 debe 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, puede declarar la función static como en la respuesta de Martin:

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

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

Oiga, compilador, cree código para esta función y permita que cualquier código en esta unidad de compilación vea la función, pero no le dé visibilidad externa. No quiero que otros módulos llamen a la función.

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

Dado que solo se usa en el archivo local, no es necesario un prototipo, por lo que no es necesario advertirle que no tiene uno.

Ahora, solo como nota… No necesita poner funciones C en las secciones @interface y @implementation de su código, ya que eso no hace nada. Esas funciones de C se compilan con exactamente la misma visibilidad y acceso, ya sea que estén dentro de las secciones de 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).

  • Gracias por la explicación detallada, pero consulte mi problema, myHandler se está registrando en el AppDelegatepero la excepción no detectada puede ocurrir en cualquier clase, por lo que no estoy seguro de si usar static es adecuado para mi…

    – Ryan

    1 de septiembre de 2012 a las 4:27

  • @Yoga: Puedes usar static aquí sin problema, porque te pasa la dirección de myHandler para NSSetUncaughtExceptionHandler. La visibilidad solo es importante para el enlazador. Si algún 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, por ejemplo, para funciones de devolución de llamada, etc.

    – Martín R.

    1 de septiembre de 2012 a las 7:46


No recibe una advertencia sobre la falta de un prototipo si declara la función como static:

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

Sí, esta es la forma correcta. Solo me pregunto por qué recibe la advertencia, ya que tengo lo mismo sin declararlo en una categoría vacía y no recibo una advertencia … Además, también puede configurar controladores de señal para capturar SIGABRT, SIGILL y SIGBUS señales:

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);
    ...
}

  • Apuesto a que tiene la advertencia deshabilitada en la configuración de compilación.

    – Jody Hagins

    31 de agosto de 2012 a las 13:37

  • Pff, sí, debo haberlo olvidado 🙂

    – más grave

    31 de agosto de 2012 a las 13:43

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad