Istnieją dwa ważne punkty modelu obsługi błędów w Swift 2: wyczerpujący i elastyczny. Razem sprowadzają się do tego, że twoje do
/ catch
stwierdzenie musi wychwycić każdy możliwy błąd, a nie tylko te, o których wiesz, że możesz je rzucić.
Zwróć uwagę, że nie deklarujesz, jakie typy błędów funkcja może zgłaszać, tylko czy w ogóle zgłasza. Jest to problem typu zero-one-infinity: jako ktoś definiujący funkcję do wykorzystania przez innych (w tym twoje przyszłe ja), nie chcesz, aby każdy klient twojej funkcji dostosowywał się do każdej zmiany w implementacji twojego funkcji, w tym jakie błędy może zgłosić. Chcesz, aby kod wywołujący twoją funkcję był odporny na takie zmiany.
Ponieważ Twoja funkcja nie może określić, jakie błędy zgłasza (lub może generować w przyszłości), catch
bloki, które wychwytują błędy, nie wiedzą, jakie typy błędów może generować. Tak więc, oprócz obsługi typów błędów, o których wiesz, musisz obsłużyć te, których nie znasz, za pomocą catch
instrukcji uniwersalnej - w ten sposób, jeśli twoja funkcja zmieni zestaw błędów, które zgłosi w przyszłości, wywołania nadal będą łapać błędy.
do {
let sandwich = try makeMeSandwich(kitchen)
print("i eat it \(sandwich)")
} catch SandwichError.NotMe {
print("Not me error")
} catch SandwichError.DoItYourself {
print("do it error")
} catch let error {
print(error.localizedDescription)
}
Ale nie poprzestawajmy na tym. Pomyśl trochę więcej o tej idei odporności. Sposób, w jaki zaprojektowałeś swoją kanapkę, musisz opisać błędy w każdym miejscu, w którym ich używasz. Oznacza to, że za każdym razem, gdy zmieniasz zestaw przypadków błędów, musisz zmieniać każde miejsce, które ich używa ... niezbyt zabawne.
Ideą definiowania własnych typów błędów jest umożliwienie scentralizowania takich rzeczy. Możesz zdefiniować description
metodę dla swoich błędów:
extension SandwichError: CustomStringConvertible {
var description: String {
switch self {
case NotMe: return "Not me error"
case DoItYourself: return "Try sudo"
}
}
}
A następnie kod obsługi błędów może poprosić o opisanie typu błędu - teraz każde miejsce, w którym obsługujesz błędy, może używać tego samego kodu i obsługiwać również możliwe przyszłe przypadki błędów.
do {
let sandwich = try makeMeSandwich(kitchen)
print("i eat it \(sandwich)")
} catch let error as SandwichError {
print(error.description)
} catch {
print("i dunno")
}
Utoruje to również drogę typom błędów (lub ich rozszerzeniom) do obsługi innych sposobów zgłaszania błędów - na przykład możesz mieć rozszerzenie typu błędu, które wie, jak przedstawić, UIAlertController
aby zgłosić błąd użytkownikowi iOS.