swift

Error Handling in Swift 3

Von am 28.02.2017

Swift ist wohl eine der größten Programmiersprachen, welche in letzter Zeit erschienen sind und erfreut sich steigender Beliebtheit. 2015 hat Apple den Sourcecode zu Swift auf Github hochgeladen und somit Open Source gemacht. Seitdem wird die Programmiersprache auch bereits serverseitig verwendet. Apple legt mit seiner Programmiersprache einen großen Fokus auf ein gutes Error Handling, um Applikationsabstürze so weit es geht zu verhindern. Mit Optionals und den zugrundeliegenden “if let”,- und “guard”- Statements gibt es schon eine Möglichkeit um nicht vorhandene Daten (leere Variablen) abzufangen. Heute möchte ich aber auf das Error Handling von Funktionen eingehen. Am besten kann man das natürlich an einem kleinen Beispiel zeigen und das werden wir uns Schritt für Schritt anschauen.

Für diesen speziellen Fall hat Swift ein leeres Protocol “Error”, welches dem Programm einen Fehler repräsentiert. Diese können am besten mit einer Enumeration (Enum) umgesetzt werden. Unsere kleine Applikation soll eine SmS oder Email an einen Kontakt schicken können. Die Logik werden wir aber nicht implementieren. Für unseren Fall schaut die Error Enumeration wie folgt aus:

enum ContactError: Error { 
   case NumberNotAvailable
   case EmailNotAvailable
}

Man könnte hier wie bei einer zusätzlichen Variable anschließen und dieser dann zum Beispiel einen String beim aufrufen übergeben.

enum ContactError: Error {
   case NumberNotAvailable(description: String)
}

Um eine Funktion jetzt abfangen zu können, müssen wir einer Funktion sagen, dass sie fehlschlagen kann. Dies passiert mittels dem Keyword “throws” und wird nach den Parametern aber vor dem Rückgabewert geschrieben.

func someFunction(someParameter: someType) throws -> someReturnType {}

In dieser Funktion haben wir nun die Möglichkeit, einen Fehler auszulösen und dann einem case aus unserer ContactError Enumeration zuzuweisen.

throw ContactError.NumberNotAvailable

// Wenn eine zusätzliche Variable vorhanden ist (wie oben definiert) dann wie folgt:
throw ContactError.NumberNotAvailable(description: "Leider ist keine Nummer angeben")

Schauen wir uns das Beispiel bis jetzt im Ganzen an:

struct Contact {
    let name: String
    let tel: Int?
    let email: String?
    func send(message: String, to contact: Contact) throws -> Message {
        guard let telNumber = contact.tel else {
            throw ContactError.NumberNotAvailable
        }
        return Message(message: message, tel: telNumber, email: nil)
    }
    func send(email: String, to contact: Contact) throws -> Message {
        guard let email = contact.email else {
            throw ContactError.EmailNotAvailable
        }
        return Message(message: email, tel: nil, email: email)
    }
}

Um eine Funktion, welche mit “throws” gekennzeichnet ist, ausführen zu können, brauchen wir auch wieder eine spezielle Syntax. Wir erstellen uns also zuerst zwei Instanzen dieser Struktur “contactA” und “contactB” und geben “contactB” nur eine E-Mail aber keine Telefonnummer. Jetzt benötigen wir einen “do-catch-block”. Im do-Block wird mittels dem Keyword “try” die Funktion aufgerufen. Wird die Funktion nicht mittels try ausgeführt dann bekommen wir einen Error in Xcode. Wenn ein Fehler gefunden wird, wird der do-block sofort abgebrochen und nach dem ansprechenden Fehler, welcher in der Funktion im Contact Struct geworfen wurde, gesucht. Es ist also möglich einen einzelnen catch-Block zu machen oder wirklich nach den verschiedenen Fehlern aus unserer ContactError-Enumeration zu suchen.

do {
    let newMessage = try contactA.send(message: "hello via textmessage", to: contactB)
} catch ContactError.NumberNotAvailable {
    print("Your contact has no number provided")
} catch ContactError.EmailNotAvailable {
    print("Your contact has no email provided")
}

In diesem Fall wird unser NumberNotAvailable Error geworfen, weil “contactB” keine Telefonnummer angegeben hat. Würden wir die Funktion

func send(email: String, to contact: Contact)

ausführen, würde diese ohne Probleme funktionieren, da bei “contactB” eine E-Mail angegeben ist. Im catch-Block ist es dann Möglich den Error entsprechend zu behandelt und zum Beispiel eine Error-Meldung anzuzeigen. Wenn kein Fehler erkannt wird, bleiben wir im do-Block und führen weitere Schritte für den Ablauf des Programmes aus.

The comments are closed.