web-dev-qa-db-ja.com

Swift)でのキャッチされないエラー/例外処理

ココアに ncaughtExceptionHandler があることは知っていますが、スイフトにも同じものを探しています。つまり、ミスのためにローカルでキャッチされないエラー/例外がアプリケーションにある場合は常に、それを適切に処理してユーザーに適切に応答できるトップレベルのアプリケーションオブジェクトまでバブルする必要があります。

Android あります。 Flex あります。 Java あります。なぜSwiftにこの重要な機能が欠けているのか疑問に思います。

13
Sunny Tambi

Swiftには、任意のランタイム例外をすべてキャッチするメカニズムはありません。理由はで説明されています

swift-usersフォーラムで。エキス:

Swiftは、技術的に不可能であるためではなく、設計者がコストが高すぎると判断したために、任意のスタックフレームを介してスローされる例外を含めないことを意識的に選択しました。

問題はこれです:エラーのためにコードの一部が早期に終了する場合、その早期終了を処理するようにコードを作成する必要があります。そうしないと、誤動作します。メモリの割り当て解除に失敗したり、ファイルハンドル/ソケット/データベース接続などを閉じなかったり、ロックを解放できなかったりします。Javaのような言語では、真に例外安全なコードを書くには、とんでもない量の試行/最終が必要です。ブロック。だから誰もやらないのです。彼らは、どの例外が発生する可能性があり、どのリソースがリークするのが危険であるかを判断し、それらの特定の予想される条件からコードを保護するだけです。その後、予期しないことが起こり、プログラムが中断します。

Swiftのような参照カウント言語では、これはさらに悪化します。例外が存在する場合に参照カウントを正しくバランスさせるには、基本的にすべての関数に、すべての保持カウントをバランスさせるための暗黙のfinallyブロックを含める必要があるためです。つまり、コンパイラは、何らかの呼び出しまたは別の呼び出しが例外をスローする可能性がない場合に、大量の追加コードを生成する必要があります。このコードの大部分は使用されることはありませんが、存在する必要があり、プロセスが肥大化します。

これらの問題のため、Swiftは従来の例外をサポートしないことを選択しました。代わりに、特別にマークされたコード領域でのみエラーをスローできます。しかし、当然の結果として、それは、スローできないコードでは本当にうまくいかず、災害を防ぐために本当にできることはクラッシュだけです。そして現在、クラッシュできるのはプロセス全体だけです。

詳細については、を参照してください。

12
Martin R

これは、すべての例外/エラーをログに記録するために使用するコードです。 Log.error(with:)は、スタックトレースを他の情報とともに保存するカスタム関数です。 Thread.callStackSymbolsは文字列の配列であり、スタックトレースを表します。

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]? = nil) -> Bool {

    NSSetUncaughtExceptionHandler { exception in
        Log.error(with: Thread.callStackSymbols)
    }

    signal(SIGABRT) { _ in
        Log.error(with: Thread.callStackSymbols)
    }

    signal(SIGILL) { _ in
        Log.error(with: Thread.callStackSymbols)
    }

    signal(SIGSEGV) { _ in
        Log.error(with: Thread.callStackSymbols)
    }

    signal(SIGFPE) { _ in
        Log.error(with: Thread.callStackSymbols)
    }

    signal(SIGBUS) { _ in
        Log.error(with: Thread.callStackSymbols)
    }

    signal(SIGPIPE) { _ in
        Log.error(with: Thread.callStackSymbols)
    }

    return true
}
13
andrei