Swift 2, если пусть с do-try-catch
В Swift 1.2 у меня есть это:
if let filePath = NSBundle.mainBundle().pathForResource("some", ofType: "txt"),
data = String(contentsOfFile: filePath, encoding: NSUTF8StringEncoding) {
for line in data.componentsSeparatedByCharactersInSet(NSCharacterSet.newlineCharacterSet()) {
// Do something
}
} else {
println("some.txt is missing")
}
В Swift 2 я больше не могу этого делать, потому что оба pathForResource
и contentsOfFile
могут бросать, а также возвращать опции. Я могу это исправить, но теперь это выглядит удивительно подробным:
do {
if let filePath = try NSBundle.... {
do {
if let data = try String.... {
for line in data..... {
// Do something
}
} else {
print("Nil data")
}
} catch {
print("contentsOfFile threw")
}
} else {
print("Nil pathForResource")
}
} catch {
print("pathForResource threw")
}
Я ожидаю, что что-то пропустил - любая помощь была оценена.
Ответы
Ответ 1
Используйте синтаксис защиты вместо if-let.
Вот пример:
do {
guard let filePath = try NSBundle .... else {
// if there is exception or there is no value
throw SomeError
}
guard let data = try String .... else {
}
} catch {
}
Разница между if-let и guard - это область развернутого значения. Если вы используете значение if-let filePath, доступно только внутри блока if-let. Если вы используете значение guard filePath, доступно для области действия, на которую вызван защитник.
Вот соответствующий раздел в быстрой книге
Оператор защиты, как и оператор if, выполняет инструкции в зависимости от на булево значение выражения. Вы используете инструкцию охраны требуют, чтобы условие было истинным, чтобы код после который будет выполнен. В отличие от утверждения if, охранник всегда имеет предложение else - код внутри предложения else выполняется, если условие не соответствует действительности.
Ответ 2
Близко, как я могу судить, только ваш инициализатор String в приведенном выше примере действительно выдает ошибку (хотя pathForResource()
может измениться после возврата необязательного значения, чтобы выбросить ошибку в какой-то момент). Поэтому ниже следует повторить то, что вы делали раньше:
if let filePath = NSBundle.mainBundle().pathForResource("some", ofType: "txt") {
do {
let data = try String(contentsOfFile: filePath, encoding: NSUTF8StringEncoding)
for line in data.componentsSeparatedByCharactersInSet(NSCharacterSet.newlineCharacterSet()) {
// Do something
}
} catch {
print("Couldn't load the file somehow")
}
} else {
print("some.txt is missing")
}
Ваша строка больше не является обязательной, поэтому там не нужно if let
.
Как указывает mustafa, оператор a guard
может быть использован для удаления уровня отступов в случае успеха:
guard let filePath = NSBundle.mainBundle().pathForResource("some", ofType: "txt") else {
print("some.txt is missing")
}
do {
let data = try String(contentsOfFile: filePath, encoding: NSUTF8StringEncoding)
for line in data.componentsSeparatedByCharactersInSet(NSCharacterSet.newlineCharacterSet()) {
// Do something
}
} catch {
print("Couldn't load the file somehow")
}
Теперь, если pathForResource()
изменилось с того, чтобы вернуть опцию, чтобы выбросить ошибку, вы можете просто использовать эти инструкции try последовательно:
do {
let filePath = try NSBundle.mainBundle().pathForResource("some", ofType: "txt")
let data = try String(contentsOfFile: filePath, encoding: NSUTF8StringEncoding)
for line in data.componentsSeparatedByCharactersInSet(NSCharacterSet.newlineCharacterSet()) {
// Do something
}
} catch {
print("some.txt is missing")
}
Первый оператор, который выдает ошибку, выйдет в этот момент, предотвращая выполнение чего-либо в прошлом. Достаточно одного оператора catch, чтобы получить что-либо из серии отказоустойчивых операций, что упрощает их цепочку.