2016-08-03 10 views
6

Ich weiß, es gibt eine UncaughtExceptionHandler in Cocoa, aber ich bin auf der Suche nach der gleichen Sache für Swift. d. h. wenn immer ein Fehler/eine Ausnahme in der Anwendung vorhanden ist, die dort aufgrund irgendeines Fehlers nicht lokal abgefangen wird, sollte sie bis zum Anwendungsobjekt der obersten Ebene gesprudelt werden, wo ich in der Lage sein sollte, sie korrekt zu handhaben und angemessen auf den Benutzer zu antworten.Uncaught Fehler/Exception Handling in Swift

Android hat es. Flex hat es. Java hat es. Ich frage mich, warum Swift diese Schlüsselfunktion vermisst.

+0

NSSetUncaughtExceptionHandler verfügbar ist, ist Swift: http://stackoverflow.com/questions/25441302/how-should-i-use-nssetuncaughtexceptionhandler-in-swift. Es fängt jedoch nur Objective-C-Ausnahmen, nicht Swift-Laufzeitfehler oder 'throw'n-Fehler. –

+0

Danke @MartinR für Ihre schnelle Antwort. Ich weiß über NSSetUncaughtExceptionHandler, dass es Objective-C-Ausnahmen behandelt. Allerdings suche ich für Swift die gleiche/ähnliche Sache. –

+0

Swift hat keinen Mechanismus, um alle Arten von Laufzeitfehlern abzufangen. Ich kann nur über den Grund raten. Zum Beispiel würde es mit der automatischen Referenzzählung nicht gut funktionieren. Sie können möglicherweise eine bessere Antwort von den Swift-Entwicklern auf einer der Mailinglisten bei swift.org erhalten. –

Antwort

8

Swift hat keinen Mechanismus, um alle willkürlichen Laufzeitausnahmen abzufangen. Die Gründe erläutert in

auf den swift-users Mailingliste. Auszug:

Swift machte eine bewusste Entscheidung nicht Ausnahmen durch beliebigen Stapelrahmen geworfen, um nicht weil es technisch unmöglich war, aber weil die Designer die Kosten beurteilt zu hoch sein.

Das Problem ist das: Wenn ein Stück Code vorzeitig beendet wird, weil einen Fehler hat, muss es geschrieben werden, um diesen frühen Ausgang zu behandeln. Sonst wird es Fehlverhalten-Fehler beim Freigeben von Speicher, Scheitern Datei zu schließen Griffen/Sockets/Datenbankverbindungen/was auch immer, nicht Sperren freigeben, usw. In einer Sprache wie Java, schreiben wirklich Ausnahme-sichere Code erfordert eine lächerliche Menge von try/finally blockt. Deshalb macht niemand es. Sie beurteilen, welche Ausnahmen sie wahrscheinlich sehen und welche Ressourcen gefährlich sind, und nur schützen ihren Code vor diesen spezifischen erwarteten Bedingungen. Dann passiert etwas unvorhergesehenes und ihr Programm bricht.

Dies ist noch schlimmer in einer Referenzzählung Sprache wie Swift, weil richtig die Referenzzahlen in Gegenwart von Ausnahmen Ausgleich grundsätzlich jede Funktion erfordert eine implizite schließlich blockieren aufzunehmen, um das Gleichgewicht der alle Zählungen behalten. Dies bedeutet, dass der Compiler viel zusätzlichen Code auf die Chance, dass einige Anrufe oder andere eine Ausnahme auslösen generiert. Die überwiegende Mehrheit dieses Codes wird nie, jemals verwendet, aber es muss da sein, Blähungen den Prozess.

Aufgrund dieser Probleme entschied Swift, keine traditionellen Ausnahmen zu unterstützen; Stattdessen können Sie nur Fehler in speziell markierten Codebereichen auslösen. Aber als Konsequenz bedeutet dies, dass wenn etwas wirklich schief geht in Code, der nicht werfen kann, kann es wirklich tun, um ein Desaster zu verhindern Absturz. Und derzeit ist das einzige, was Sie zum Absturz bringen können, der gesamte Prozess.

Für weitere Informationen siehe

+1

Danke @MartinR ... Ich habe festgestellt, dass Swift-Jungs die Last, jede einzelne kleine oder große Ausnahme und jeden Fehler zu umgehen, den Entwicklern "per Design" übertragen hat. –

+1

Vielen Dank für das Teilen, jetzt ist zumindest der Grund für eine scheinbar verwirrende Unterlassung klar. – Crashalot

+2

Das ist okay für mich, aber ich muss zumindest noch die Signale abfangen können, damit ich meinen Crashlogger implementieren kann. Es scheint aber nicht zu funktionieren. force dewrapping nil löst eine 'EXC_BAD_INSTRUCTION' aus, die ich weder mit Exception noch mit Signalhandlern abfangen kann ... –

5

Dies ist der Code, den ich alle Ausnahmen/Fehler zu protokollieren verwenden. Log.error(with:) ist eine benutzerdefinierte Funktion, wo ich den Stack-Trace zusammen mit anderen Informationen speichern. Thread.callStackSymbols ist ein Array von Strings und stellt den Stack-Trace dar.

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) 
    } 
+0

Vielen Dank, wusste nicht einmal über Signal (...) Funktion –

+1

Beachten Sie, dass nur" async-signalsafe " "Funktionen können in Signalverarbeitern sicher aufgerufen werden. "printf" und verwandte Funktionen sind nicht async-signalsicher. –

+0

Wo verwenden Sie diesen Code? AppDelegieren? Main? Ich habe versucht, diesen Code ohne Erfolg zu meiner App hinzuzufügen. –