2012-08-31 13 views
5

Il mio codice per la registrazione del gestore di eccezioni non rilevate utilizzando UncaughtExceptionHandler è il seguente, pensi che ci sia qualche potenziale problema?Registro UncaughtExceptionHandler nell'obiettivo C utilizzando NSSetUncaughtExceptionHandler

@interface AppDelegate() 

void myHandler(NSException * exception); 

@end 

@implementation AppDelegate 

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

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

È possibile avere un modo più conciso per scriverlo?

ho bisogno di usare l'estensione di classe per dichiarare prototipo al fine di sbarazzarsi del monito di Nessun precedente prototipo per la funzione ..

risposta

10

Martin è corretta. Tuttavia, ho pensato di elaborare solo un po ', per spiegare perché è così.

La definizione della funzione:

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

definisce una funzione che sarà visibile esternamente. In altre parole (generalizzate, non tecniche), verrà creato un simbolo nel file oggetto in modo che il linker possa trovarlo, il che consente agli altri file di chiamare myHandler.

Tuttavia, poiché dovrebbe essere visibile esternamente, altri file dovranno conoscere l'aspetto di tale funzione. È qui che entra in gioco il prototipo. L'avvertimento è sostanzialmente dicendo ...

Ehi, hanno dichiarato questa funzione per essere visibile esternamente ad altro codice , ma non vedo un prototipo che altro codice può utilizzare per sapere sulla funzione.

Quindi, si ottiene un avviso. È un buon avvertimento da avere. Ti aiuta a ricordare di dichiarare i prototipi per le funzioni che vuoi esportare.

Ora, come hai scoperto, puoi dichiarare un prototipo e l'avviso scompare. Tuttavia, dichiarare il prototipo solo nel file di implementazione dovrebbe essere un altro avvertimento. Questo avviso personale dovrebbe essere:

Vuoi realmente che questa funzione abbia visibilità esterna o venga semplicemente chiamata in questa unità di compilazione? Se la funzione non avrà visibilità esterna, non è necessario esportarla nella tabella dei simboli e non è necessario un prototipo che altri moduli possano includere per conoscere la funzione.

In tal caso, è possibile dichiarare la funzione static come nella risposta di Martin:

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

In questo contesto, static dice al compilatore qualcosa come:

Ehi, compilatore, creare il codice per questa funzione, e consentire qualsiasi codice in questa unità di compilazione per vedere la funzione, ma non dargli visibilità esterna . Non voglio che la funzione venga chiamata da altri moduli.

In questo caso, anche se altro codice dichiarato il prototipo, si sarebbero non viene visualizzata la funzione perché è "privato" per il file in cui è definito.

Poiché viene utilizzato solo nel file locale, non è necessario un prototipo, quindi non è necessario avvisare che non ne è disponibile uno.

Ora, proprio come una nota ... Non è necessario inserire le funzioni C nelle sezioni @interface e @implementation del codice, in quanto non fa nulla. Queste funzioni C sono compilate con la stessa identica visibilità e accesso se esse si trovano all'interno delle sezioni ObjC o meno.

Infine, se lo desideri, puoi disabilitare questo avviso nelle impostazioni di build di Xcode (ma ora che hai compreso il contesto dell'avvertimento, ti suggerisco di lasciarlo acceso).

+0

+1 Ottima spiegazione, come al solito. –

+1

Grazie per la spiegazione dettagliata, ma fai riferimento al mio problema, 'myHandler' è stato registrato in' AppDelegate', ma un'eccezione non rilevata può accadere in qualsiasi classe, quindi non sono sicuro che l'uso di 'static' sia giusto per me .. – Ryan

+2

@Yoga: È possibile utilizzare 'static' qui senza problemi, perché si passa l'indirizzo di' myHandler' a 'NSSetUncaughtExceptionHandler'. La visibilità è importante solo per il linker. Se qualche modulo ha l'indirizzo di 'myHandler', può chiamare questa funzione indipendentemente dalla visibilità. - Passare l'indirizzo di una funzione statica locale ad altre funzioni è un modello comune, ad es. per le funzioni di callback ecc. –

0

Sì, questo è il modo corretto. Mi sto solo chiedendo perché ricevi l'avvertimento perché ho la stessa cosa senza dichiararlo in una categoria vuota e non ricevo un avviso ... Inoltre puoi anche impostare i gestori di segnale per catturare i segnali SIGABRT, SIGILL e 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

Scommetto che hai disattivato l'avviso nelle impostazioni di generazione. –

+0

Pff, sì, devo aver dimenticato :) – graver

3

non si ottiene un avvertimento circa un prototipo mancante se si dichiara la funzione come static: risposta

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

+1 Giusto, come al solito. –

Problemi correlati