Подтвердить что ты не робот

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

Я ожидаю, что что-то пропустил - любая помощь была оценена.

4b9b3361

Ответ 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, чтобы получить что-либо из серии отказоустойчивых операций, что упрощает их цепочку.