Swift Language
Obsługa błędów
Szukaj…
Uwagi
Aby uzyskać więcej informacji o błędach, zobacz Swift Programming Language .
Podstawy obsługi błędów
Funkcje w Swift mogą zwracać wartości, zgłaszać błędy lub oba:
func reticulateSplines() // no return value and no error
func reticulateSplines() -> Int // always returns a value
func reticulateSplines() throws // no return value, but may throw an error
func reticulateSplines() throws -> Int // may either return a value or throw an error
Każda wartość zgodna z protokołem ErrorType (w tym obiekty NSError) może zostać zgłoszona jako błąd. Wyliczenia zapewniają wygodny sposób definiowania niestandardowych błędów:
enum NetworkError: ErrorType {
case Offline
case ServerError(String)
}
enum NetworkError: Error {
// Swift 3 dictates that enum cases should be `lowerCamelCase`
case offline
case serverError(String)
}
Błąd wskazuje na niekrytyczną awarię podczas wykonywania programu i jest obsługiwany za pomocą wyspecjalizowanych konstrukcji kontrolujących przepływ do
catch
/ catch
, throw
i try
.
func fetchResource(resource: NSURL) throws -> String {
if let (statusCode, responseString) = /* ...from elsewhere...*/ {
if case 500..<600 = statusCode {
throw NetworkError.serverError(responseString)
} else {
return responseString
}
} else {
throw NetworkError.offline
}
}
Błędy można wychwycić za pomocą do
/ catch
:
do {
let response = try fetchResource(resURL)
// If fetchResource() didn't throw an error, execution continues here:
print("Got response: \(response)")
...
} catch {
// If an error is thrown, we can handle it here.
print("Whoops, couldn't fetch resource: \(error)")
}
Każda funkcja, która może zgłosić błąd, musi zostać wywołana przy użyciu try
, try?
lub try!
:
// error: call can throw but is not marked with 'try'
let response = fetchResource(resURL)
// "try" works within do/catch, or within another throwing function:
do {
let response = try fetchResource(resURL)
} catch {
// Handle the error
}
func foo() throws {
// If an error is thrown, continue passing it up to the caller.
let response = try fetchResource(resURL)
}
// "try?" wraps the function's return value in an Optional (nil if an error was thrown).
if let response = try? fetchResource(resURL) {
// no error was thrown
}
// "try!" crashes the program at runtime if an error occurs.
let response = try! fetchResource(resURL)
Łapanie różnych typów błędów
Utwórzmy własny typ błędu dla tego przykładu.
enum CustomError: ErrorType {
case SomeError
case AnotherError
}
func throwing() throws {
throw CustomError.SomeError
}
enum CustomError: Error {
case someError
case anotherError
}
func throwing() throws {
throw CustomError.someError
}
Składnia Do-Catch pozwala wyłapać zgłoszony błąd i automatycznie tworzy stały error
nazwie dostępny w bloku catch
:
do {
try throwing()
} catch {
print(error)
}
Możesz także samodzielnie zadeklarować zmienną:
do {
try throwing()
} catch let oops {
print(oops)
}
Możliwe jest również łączenie różnych instrukcji catch
. Jest to wygodne, jeśli w bloku Do można zgłosić kilka rodzajów błędów.
W tym przypadku Do-Catch spróbuje najpierw rzucić błąd jako CustomError
, a następnie jako NSError
jeśli typ niestandardowy nie został dopasowany.
do {
try somethingMayThrow()
} catch let custom as CustomError {
print(custom)
} catch let error as NSError {
print(error)
}
W Swift 3 nie trzeba jawnie spuszczać do NSError.
do {
try somethingMayThrow()
} catch let custom as CustomError {
print(custom)
} catch {
print(error)
}
Wzór przechwytywania i przełączania do obsługi jawnych błędów
class Plane {
enum Emergency: ErrorType {
case NoFuel
case EngineFailure(reason: String)
case DamagedWing
}
var fuelInKilograms: Int
//... init and other methods not shown
func fly() throws {
// ...
if fuelInKilograms <= 0 {
// uh oh...
throw Emergency.NoFuel
}
}
}
W klasie klienta:
let airforceOne = Plane()
do {
try airforceOne.fly()
} catch let emergency as Plane.Emergency {
switch emergency {
case .NoFuel:
// call nearest airport for emergency landing
case .EngineFailure(let reason):
print(reason) // let the mechanic know the reason
case .DamagedWing:
// Assess the damage and determine if the president can make it
}
}
Wyłączanie propagacji błędów
Twórcy Swift poświęcili wiele uwagi, aby język był ekspresyjny, a obsługa błędów jest dokładnie taka, ekspresyjna. Jeśli spróbujesz wywołać funkcję, która może zgłosić błąd, wywołanie funkcji musi być poprzedzone słowem kluczowym try. Słowo kluczowe try nie jest magiczne. Wszystko, co robi, to uświadomienie programistom zdolności rzucania funkcją.
Na przykład poniższy kod używa funkcji loadImage (atPath :), która ładuje zasób obrazu pod daną ścieżką lub zgłasza błąd, jeśli obrazu nie można załadować. W takim przypadku, ponieważ obraz jest dostarczany z aplikacją, w czasie wykonywania nie zostanie zgłoszony żaden błąd, dlatego należy wyłączyć propagację błędów.
let photo = try! loadImage(atPath: "./Resources/John Appleseed.jpg")
Utwórz niestandardowy błąd ze zlokalizowanym opisem
Utwórz enum
niestandardowych błędów
enum RegistrationError: Error {
case invalidEmail
case invalidPassword
case invalidPhoneNumber
}
Utwórz extension
RegistrationError
aby obsłużyć zlokalizowany opis.
extension RegistrationError: LocalizedError {
public var errorDescription: String? {
switch self {
case .invalidEmail:
return NSLocalizedString("Description of invalid email address", comment: "Invalid Email")
case .invalidPassword:
return NSLocalizedString("Description of invalid password", comment: "Invalid Password")
case .invalidPhoneNumber:
return NSLocalizedString("Description of invalid phoneNumber", comment: "Invalid Phone Number")
}
}
}
Błąd obsługi:
let error: Error = RegistrationError.invalidEmail
print(error.localizedDescription)