попробуй, попробуй! & пытаться? какая разница, и когда использовать каждый?

172

В Swift 2.0 Apple представила новый способ обработки ошибок (do-try-catch). И несколько дней назад в бета-версии 6 было введено еще более новое ключевое слово ( try?). Кроме того, знал, что я могу использовать try!. В чем разница между тремя ключевыми словами и когда их использовать?

Абдуррахман
источник

Ответы:

316

Обновлено для Swift 5.1

Предположим следующую функцию броска:

enum ThrowableError: Error {

    case badError(howBad: Int)
}

func doSomething(everythingIsFine: Bool = false) throws -> String {

  if everythingIsFine {
      return "Everything is ok"
  } else {
      throw ThrowableError.badError(howBad: 4)
  }
}

пытаться

У вас есть 2 варианта, когда вы пытаетесь вызвать функцию, которая может выдать.

Вы можете взять на себя ответственность за обработку ошибок , окружив свой вызов блоком do-catch:

do {
    let result = try doSomething()
}
catch ThrowableError.badError(let howBad) {
    // Here you know about the error
    // Feel free to handle or to re-throw

    // 1. Handle
    print("Bad Error (How Bad Level: \(howBad)")

    // 2. Re-throw
    throw ThrowableError.badError(howBad: howBad)
}

Или просто попробуйте вызвать функцию и передать ошибку следующему абоненту в цепочке вызовов:

func doSomeOtherThing() throws -> Void {    
    // Not within a do-catch block.
    // Any errors will be re-thrown to callers.
    let result = try doSomething()
}

пытаться!

Что происходит, когда вы пытаетесь получить доступ к неявно развернутому необязательному файлу с нулем внутри него? Да, правда, приложение будет CRASH! То же самое и с попыткой! он в основном игнорирует цепочку ошибок и объявляет ситуацию «сделай или умри». Если вызванная функция не выдает никаких ошибок, все идет хорошо. Но если произошел сбой и возникла ошибка, ваше приложение просто вылетит .

let result = try! doSomething() // if an error was thrown, CRASH!

пытаться?

Новое ключевое слово, которое было введено в бета-версии Xcode 7. Оно возвращает необязательное значение, которое разворачивает успешные значения, и возвращает ошибку, возвращая nil.

if let result = try? doSomething() {
    // doSomething succeeded, and result is unwrapped.
} else {
    // Ouch, doSomething() threw an error.
}

Или мы можем использовать охрану:

guard let result = try? doSomething() else {
    // Ouch, doSomething() threw an error.
}
// doSomething succeeded, and result is unwrapped.

Последнее замечание здесь, используя try?примечание, что вы отбрасываете произошедшую ошибку, поскольку она переведена в ноль. Используйте попробовать? когда вы концентрируетесь больше на успехах и неудачах, а не на том, почему что-то не получилось.

Использование оператора объединения

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

let result = (try? doSomething()) ?? "Default Value"
print(result) // Default Value
Абдуррахман
источник
Ваш второй пример кода ( let result = try doSomething() // Not within a do-catch block) должен вызываться из метода, который объявлен как throws, верно? Так что, если doSomething()не получается, то работает ли и внешний метод (в свою очередь)?
Николас Миари
Старый поток и все, но я нашел, что сегодня (Swift 4, Xcode 9.1) попробовать? не разворачивает результат автоматически. Это просто оставляет за собой обычную опцию для вас, чтобы развернуть вручную. Не уверен, что это изменилось после Swift 2/3, но это в соответствии с docs: developer.apple.com/library/content/documentation/Swift/… (см. Преобразование ошибок в дополнительные значения ). Отличное объяснение попробовать кстати.
the_dude_abides
1
в swift 4 попробуйте? не удаляет вызовы броска функций, возникающие в выражениях try в моем проекте.
aznelite89
7
Вы также можете использовать try?с ??таким образом, чтобы он позволил вам определить значение по умолчанию в одной строке:let something:String = (try? whateverIfItThrows()) ?? "Your default value here"
itMaxence