5

キャッチされていない例外ハンドラーを登録するための私のコードUncaughtExceptionHandlerは次のとおりですが、潜在的な問題があると思いますか?

@interface AppDelegate ()

void myHandler(NSException * exception);

@end

@implementation AppDelegate

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

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

もっと簡潔に書く方法はありますか?

関数の以前のプロトタイプがありませんという警告を取り除くために、クラス拡張を使用してプロトタイプを宣言する必要があります。

4

3 に答える 3

11

マーティンの答えは正しいです。しかし、なぜそうなのかを説明するために、少し詳しく説明したいと思いました。

あなたの関数定義:

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

外部から見える関数を定義します。他の(一般化された、非技術的な)言葉で言えば、オブジェクトファイルにシンボルが作成され、リンカーがそれを見つけることができるようになり、他のファイルがmyHandler.

ただし、外部から見えるはずなので、他のファイルはその機能がどのように見えるかを知る必要があります。そこでプロトタイプの出番です。警告は基本的に言っています...

ねえ、あなたはこの関数を他のコードから外部から見えるように宣言しましたが、他のコードが関数について知るために使用できるプロトタイプが見つかりません。

したがって、警告が表示されます。着用するのは良い警告です。エクスポートする関数のプロトタイプを宣言することを覚えておくのに役立ちます。

発見したように、プロトタイプを宣言すると、警告が消えます。ただし、実装ファイルだけでプロトタイプを宣言すると、別の警告が表示されます。その個人的な警告は次のとおりです。

この関数に外部可視性を持たせたいですか、それともこのコンパイル単位で呼び出されるだけですか? 関数が外部可視性を持たない場合、それをシンボル テーブルにエクスポートする必要はなく、他のモジュールが関数を認識できるように含めることができるプロトタイプも必要ありません。

その場合、staticMartin の応答のように関数を宣言できます。

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

このコンテキストでstaticは、コンパイラに次のように伝えます。

コンパイラさん、この関数のコードを作成し、このコンパイル ユニット内のすべてのコードが関数を認識できるようにしますが、外部からの可視性は与えないでください。関数が他のモジュールから呼び出されないようにします。

この場合、他のコードがプロトタイプを宣言したとしても、関数が定義されているファイルに対して「プライベート」であるため、関数は表示されません。

ローカルファイルでのみ使用されているため、プロトタイプは必要ありません。したがって、プロトタイプがないことを警告する必要はありません。

さて、メモとして...コードの @interface セクションと @implementation セクションに C 関数を配置する必要はありません。何もしないからです。これらの C 関数は、ObjC セクション内にあるかどうかに関係なく、まったく同じ可視性とアクセスでコンパイルされます。

最後に、必要に応じて、Xcode ビルド設定でこの警告を無効にすることができます (ただし、警告のコンテキストを理解したので、有効にしておくことをお勧めします)。

于 2012-08-31T13:36:25.633 に答える
3

static関数を次のように宣言すると、プロトタイプが見つからないという警告は表示されません。

static void myHandler(NSException * exception)
{
  // ...
}
于 2012-08-31T12:44:22.157 に答える
0

はい、これは正しい方法です。空のカテゴリで宣言せずに同じものがあり、警告が表示されないのに、なぜ警告が表示されるのか疑問に思っています...さらに、信号ハンドラをキャッチするように設定して、信号を送信することもできSIGABRTます。SIGILLSIGBUS

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);
    ...
}
于 2012-08-31T12:40:01.387 に答える