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:

2.0 2.2
enum NetworkError: ErrorType {
    case Offline
    case ServerError(String)
}
3.0
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.

2.2
enum CustomError: ErrorType {
    case SomeError
    case AnotherError
}

func throwing() throws {
    throw CustomError.SomeError
}
3.0
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.

2.2
do {
    try somethingMayThrow()
} catch let custom as CustomError {
    print(custom)
} catch let error as NSError {
    print(error)
}
3.0

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)


Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow