Поиск…


замечания

Дополнительные сведения об ошибках см. В разделе Быстрый язык программирования .

Основы обработки ошибок

Функции в Swift могут возвращать значения, бросать ошибки или и то, и другое:

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

Любое значение, которое соответствует протоколу ErrorType (включая объекты NSError), может быть выбрано как ошибка. Перечисления обеспечивают удобный способ определения пользовательских ошибок:

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

Ошибка указывает на нефатальный сбой во время выполнения программы и обрабатывается специализированными конструкциями потока управления do / catch , throw и 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
    }
}

Ошибки могут быть обнаружены с помощью 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)")
}

Любая функция, которая может вызвать ошибку, должна вызываться с помощью try , try? , или 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)

Поиск различных типов ошибок

Давайте создадим наш собственный тип ошибки для этого примера.

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
}

Синтаксис Do-Catch позволяет поймать заброшенную ошибку и автоматически создает постоянную именованную error доступную в блоке catch :

do {
    try throwing()
} catch {
    print(error)
}

Вы также можете объявить переменную самостоятельно:

do {
    try throwing()
} catch let oops {
    print(oops)
}

Это также возможно цепь различных catch отчетности. Это удобно, если в блоке Do можно выбросить несколько типов ошибок.

Здесь Do-Catch сначала попытается передать ошибку как CustomError , а затем как NSError если пользовательский тип не был сопоставлен.

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

В Swift 3 нет необходимости явно отключать NSError.

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

Схема улова и переключения для явной обработки ошибок

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
        }
    }

}

В классе клиента:

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
    }
}

Отключение распространения ошибок

Создатели Swift уделяют много внимания тому, чтобы сделать язык выразительным, а обработка ошибок - это именно то, что выразительно. Если вы попытаетесь вызвать функцию, которая может выдать ошибку, вызов функции должен предшествовать ключевому слову try. Ключевое слово try не является волшебным. Все, что он делает, делает разработчик осведомленным о способности бросать функцию.

Например, следующий код использует функцию loadImage (atPath :), которая загружает ресурс изображения по заданному пути или выдает ошибку, если изображение не может быть загружено. В этом случае, поскольку изображение поставляется вместе с приложением, во время выполнения не будет выдаваться ошибка, поэтому целесообразно отключить распространение ошибок.

let photo = try! loadImage(atPath: "./Resources/John Appleseed.jpg")

Создание пользовательской ошибки с локализованным описанием

Создать enum пользовательских ошибок

enum RegistrationError: Error {
    case invalidEmail
    case invalidPassword
    case invalidPhoneNumber
}

Создайте extension RegistrationError для обработки описания Localized.

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")
        }
    }
}

Ошибка обработки:

let error: Error = RegistrationError.invalidEmail
print(error.localizedDescription)


Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow