Свифт гвардии сайта

Swift 2 представил guard ключевое слово, которое может использоваться для обеспечения готовности различных данных. Пример, который я видел на этот сайт демонстрирует функцию submitTapped:

func submitTapped() {
    guard username.text.characters.count > 0 else {
        return
    }

    print("All good")
}

мне интересно, если с помощью guard отличается от того, чтобы делать это старомодным способом, используя if состояние. Дает ли это преимущества, которые вы не могли бы получить, используя простой чек?

12 ответов


чтение в этой статье я заметил большие преимущества, используя гвардии

здесь вы можете сравнить использование guard с примером:

это часть без охраны:

func fooBinding(x: Int?) {
    if let x = x where x > 0 {
        // Do stuff with x
        x.description
    }

    // Value requirements not met, do something
}
  1. здесь вы помещаете желаемый код во все условия

    вы можете не сразу увидеть проблему с этим, но вы можете себе представить, насколько запутанной она может стать, если она была вложена с многочисленными условиями что все должно быть выполнено, прежде чем запускать ваши заявления

способ очистить это-сначала выполнить каждую из ваших проверок и выйти, если они не выполнены. Это позволяет легко понять, какие условия заставят эту функцию выйти.

но теперь мы можем использовать guard, и мы видим, что можно решить некоторые проблемы:

func fooGuard(x: Int?) {
    guard let x = x where x > 0 else {
        // Value requirements not met, do something
        return
    }

    // Do stuff with x
    x.description
}
  1. проверка состояния, которое вы хотите, а не тот, который вы не. Это снова похоже к утверждению. Если условие не выполнено, выполняется оператор else guard, который выходит из функции.
  2. если условие проходит, то опционная переменная здесь автоматически развернута для вас внутри объем который предохранитель был вызван оператор-в этом случае функция fooGuard (_:).
  3. вы проверяете плохие случаи рано, что делает вашу функцию более читаемой и проще в обслуживании

эта же закономерность сохраняется true для необязательных значений:

func fooNonOptionalGood(x: Int) {
    guard x > 0 else {
        // Value requirements not met, do something
        return
    }

    // Do stuff with x
}

func fooNonOptionalBad(x: Int) {
    if x <= 0 {
        // Value requirements not met, do something
        return
    }

    // Do stuff with x
}

если у вас остались какие-либо вопросы вы можете прочитать всю статью: заявление Swift guard.

Подводя Итоги

и, наконец, чтение и тестирование я обнаружил, что если вы используете guard, чтобы развернуть любые optionals,

эти развернутые значения остаются вокруг для вас, чтобы использовать в остальной части вашего блок кода

.

guard let unwrappedName = userName else {
    return
}

print("Your username is \(unwrappedName)")

здесь развернутое значение будет доступно только внутри блока if

if let unwrappedName = userName {
    print("Your username is \(unwrappedName)")
} else {
    return
}

// this won't work – unwrappedName doesn't exist here!
print("Your username is \(unwrappedName)")

В отличие от if, guard создает переменную, к которой можно получить доступ извне ее блока. Полезно развернуть много Optionals.


есть два больших преимущества guard. Один избегает пирамиды судьбы, как уже упоминали другие-много раздражает if let операторы, вложенные друг в друга, движутся все дальше и дальше вправо.

другое преимущество часто логика, которую вы хотите реализовать, больше"if not let" чем "if let { } else".

вот пример: Предположим, вы хотите реализовать accumulate – между map и reduce где он возвращает вам массив под управлением уменьшает. Вот он с guard:

extension Sliceable where SubSlice.Generator.Element == Generator.Element {

    func accumulate(combine: (Generator.Element,Generator.Element)->Generator.Element) -> [Generator.Element] {
        // if there are no elements, I just want to bail out and
        // return an empty array
        guard var running = self.first else { return [] }

        // running will now be an unwrapped non-optional
        var result = [running]

        // dropFirst is safe because the collection
        // must have at least one element at this point
        for x in dropFirst(self) {
            running = combine(running, x)
            result.append(running)
        }
        return result
    }

}


let a = [1,2,3].accumulate(+)  // [1,3,6]
let b = [Int]().accumulate(+)  // []

как бы ты написал без гвардии, но все еще используя first что возвращает необязательный? Что-то вроде этого:--14-->

extension Sliceable where SubSlice.Generator.Element == Generator.Element {

    func accumulate(combine: (Generator.Element,Generator.Element)->Generator.Element) -> [Generator.Element] {

        if var running = self.first  {
            var result = [running]

            for x in dropFirst(self) {
                running = combine(running, x)
                result.append(running)
            }
            return result
        }
        else {
            return []
        }
    }

}

дополнительная вложенность раздражает, но также не так логично иметь if и else так далеко друг от друга. Гораздо более читабельно иметь ранний выход для пустого случая, а затем продолжить с остальной частью функции, как если бы это не было возможность.


при выполнении условия с помощью guard Он предоставляет переменные, объявленные в guard блок для остальной части кода-блока, приведя их в свою область. Который, как уже говорилось ранее, обязательно пригодится с вложенными if let заявления.

обратите внимание, что guard требует возвращение или бросить в своем заявлении else.

разбор JSON с Guard

Ниже приведен пример того, как можно проанализировать объект JSON, используя охранять, а не если-пускай. Это выдержка из записи в блоге, которая включает в себя файл playground, который вы можете найти здесь:

как использовать Guard в Swift 2 для разбора JSON

func parseJSONWithGuard(data : [String : AnyObject]) throws -> Developer {

    guard let firstname = data["First"] as? String  else {
        return Developer() // we could return a nil Developer()
    }

    guard let lastname = data["Last"] as? String else {
        throw ParseError.BadName // or we could throw a custom exception and handle the error
    }

    guard let website = data["WebSite"] as? String else {
        throw ParseError.BadName
    }

    guard let iosDev = data["iosDeveloper"] as? Bool else {
        throw ParseError.BadName
    }



    return Developer(first: firstname, last: lastname, site: website, ios: iosDev)

}

скачать playground:воспитатель

Подробнее:

вот отрывок из Руководство По Языку Программирования Swift:

если условие заявления предохранителя выполнено, выполнение кода продолжается после заявления охранника закрывается скоба. Любые переменные или константы которые были присвоены значения, используя необязательную привязку как часть условие доступно для остальной части блока кода, который охранник появляется заявление.

если это условие не выполняется, код внутри else выполняется выполненный. Эта ветвь должна передать управление для выхода из блока кода что это заявление охранника появляется. Это можно сделать с контроля передача оператор, такой как return, break или continue, или может вызывать функция или метод, который не возвращается, например fatalError().


одним из преимуществ является устранение вложенные if let заявления. См. видео WWDC "What's New in Swift" около 15: 30, раздел под названием "Пирамида судьбы".


С помощью гвардии наше намерение ясно. мы не хотим выполнять остальную часть кода, если это конкретное условие не выполняется. здесь мы можем расширить цепь тоже, пожалуйста, посмотрите на ниже кода:

guard let value1 = number1, let value2 = number2 else { return }
 // do stuff here

когда использовать guards

если у вас есть контроллер вида с несколькими элементами UITextField или другим типом пользовательского ввода, вы сразу заметите, что вы должны развернуть текстовое поле.текст необязательно, чтобы добраться до текста внутри (если есть!). isEmpty не принесет вам никакой пользы здесь, без ввода текстовое поле просто вернет ноль.

таким образом, у вас есть несколько из них, которые вы разворачиваете и в конечном итоге передаете функции, которая отправляет их на конечную точку сервера. Мы не хотим код сервера должен иметь дело с нулевыми значениями или ошибочно отправлять недопустимые значения на сервер, поэтому мы сначала развернем эти входные значения с помощью guard.

func submit() {
    guard let name = nameField.text else {
        show("No name to submit")
        return
    }

    guard let address = addressField.text else {
        show("No address to submit")
        return
    }

    guard let phone = phoneField.text else {
        show("No phone to submit")
        return
    }

    sendToServer(name, address: address, phone: phone)
}

func sendToServer(name: String, address: String, phone: String) {
  ...
}

вы заметите, что наша функция связи с сервером принимает необязательные строковые значения в качестве параметров, поэтому guard разворачивает заранее. Разворачивание немного неинтуитивно, потому что мы привыкли разворачивать с if let, который разворачивает значения для использования внутри блока. Здесь оператор guard имеет связанный блок, но на самом деле это блок else - то есть то, что вы делаете, если разворачивание не удается - значения разворачиваются прямо в тот же контекст, что и сам оператор.

// разделение интересов

без охранника

без использования guard, мы бы в конечном итоге с большой кучей кода, который напоминает пирамида судьбы. Это не очень хорошо масштабируется для добавления новых полей в нашу форму или для очень читаемого кода. Отступ может быть трудно следовать, особенно с таким количеством других утверждений на каждой развилке.

func nonguardSubmit() {
    if let name = nameField.text {
        if let address = addressField.text {
            if let phone = phoneField.text {
                sendToServer(name, address: address, phone: phone)
            } else {
                show("no phone to submit")
            }
        } else {
            show("no address to submit")
        }
    } else {
        show("no name to submit")
    }
}

Да, мы могли бы даже объединить все это, если бы операторы let в один оператор, разделенный запятыми, но мы потеряли бы возможность выяснить, какой оператор не удался и представить сообщение пользователю.

https://thatthinginswift.com/guard-statement-swift/


охранник заявление собирается сделать . это пара разных

1) это позволяет мне уменьшить вложенный оператор if
2) это увеличивает мою область, которая доступна моей переменной

если заявление

func doTatal(num1 : Int?, num2: Int?) {
  // nested if statement
    if let fistNum = num1 where num1 > 0 {
        if let lastNum = num2 where num2 < 50 {

          let total = fistNum + lastNum
        }
    }
 // don't allow me to access out of the scope 
 //total = fistNum + lastNum 
}

заявление охранника

func doTatal(num1 : Int?, num2: Int?) {
   //reduce  nested if statement and check positive way not negative way 
    guard let fistNum = num1 where num1 > 0 else{
      return
    }
    guard  let lastNum = num2 where num2 < 50 else {
     return
    }
    // increase my scope which my variable accessible
    let total = fistNum + lastNum

}

из документации Apple:

Заявление Охранника

оператор guard используется для передачи управления программой из области, если одно или несколько условий не выполнены.

Synatx:

guard condition else {
    statements
}

преимущество:

1. Используя guard оператор мы можем избавиться от глубоко вложенных условных обозначений, единственная цель-проверка набора требований.

2. Он был разработан специально для раннего выхода из метода или функции.

если вы используете, если ниже приведен код, как он выглядит.

  let task = URLSession.shared.dataTask(with: request) { (data, response, error) in

        if error == nil {
            if let  statusCode = (response as? HTTPURLResponse)?.statusCode, statusCode >= 200 && statusCode <= 299 {
                if let data = data {

                    //Process Data Here.
                    print("Data: \(data)")

                } else {
                    print("No data was returned by the request!")
                }
            } else {
                print("Your request returned a status code other than 2XX!")
            }
        } else {
            print("Error Info: \(error.debugDescription)")
        }
    }
    task.resume()

использование guard вы можете передать управление из области, если одно или несколько условий не выполнены.

let task = URLSession.shared.dataTask(with: request) { (data, response, error) in

            /* GUARD: was there an error? */
            guard (error == nil) else {
                print("There was an error with your request: \(error)")
                return
            }

            /* GUARD: Did we get a successful 2XX response? */
            guard let statusCode = (response as? HTTPURLResponse)?.statusCode, statusCode >= 200 && statusCode <= 299 else {
                print("Your request returned a status code other than 2XX!")
                return
            }

            /* GUARD: was there any data returned? */
            guard let data = data else {
                print("No data was returned by the request!")
                return
            }

            //Process Data Here.
            print("Data: \(data)")
}
task.resume()

ссылки:

1. Swift 2: Выход рано с охраной 2. Udacity 3. Заявление Охранника


это действительно действительно делает поток последовательности с несколькими поисками и optionals гораздо более кратким и ясным и уменьшает много вложенности. См. Erica Sadun post при замене Ifs. .... Может увлечься, пример ниже:

    let filteredLinks = locationsLinkedToList.filter({.actionVerb == movementCommand})
    guard let foundLink = filteredLinks.first else {return ("<Person> cannot go in that direction.", nil, nil)}
    guard filteredLinks.count == 1 else {return ("<Person> cannot decide which route to take.", nil, nil)}
    guard let nextLocation = foundLink.toLocation else {return ("<Person> cannot go in that direction.", nil, nil)}

посмотрите, если это прилипает.


как оператор if, guard выполняет операторы на основе логического значения выражения. В отличие от оператора if, операторы guard выполняются только в том случае, если условия не выполнены. Вы можете думать о guard больше как Assert, но вместо того, чтобы врезаться, вы можете изящно выйти.

см.: http://ericcerney.com/swift-guard-statement/


проще говоря, он предоставляет способ проверки полей перед выполнением. Это хороший стиль программирования, поскольку он повышает читаемость. В других языках это может выглядеть так:

func doSomething() {
    if something == nil {
        // return, break, throw error, etc.
    }
    ...
}

но поскольку Swift предоставляет вам optionals, мы не можем проверить, если это nil и присвоить значение переменной. В отличие от этого, if let проверяет, что это не nil и присваивает переменную для хранения фактического значения. Вот где guard вступает в игру. Это дает вы более лаконичный способ выхода из раннего использование опциями.