Що означає закриття @escaping та @nonescaping у Swift?

Під час дії коду, коли ви працюєте з функціями, вони можуть працювати з атрибутами @escaping або @nonescaping. Ви коли-небудь давали час на роздуми, що це означає? Отже, тут ми будемо обговорювати ці терміни.

Що таке закриття?

Закриття - це самостійні блоки функціональності, які можна передавати і використовувати у вашому коді.

У Swift 1.x та Swift 2.x параметр закриття за замовчуванням був @escaping, означає, що закриття може бути уникнути під час виконання корпусу функції. якщо ви не хочете уникати параметрів закриття, позначте його як @nonescaping.

У Swift 3.x Apple внесла зміни: параметри закриття за замовчуванням стали @nonescaping, закриття також буде виконано з тілом функції, якщо хочеться виконати закриття, позначивши його як @escaping. Чому Apple внесла цю зміну? Давайте обговоримо це наприкінці дискусії .

1. @nonescaping закриття:

При передачі закриття в якості аргументу функції закриття виконується з тілом функції і повертає компілятор назад. По закінченню виконання пройдене закриття виходить за межі і більше не існує в пам'яті.

Життєвий цикл закриття @nonescaping:
 1. Передайте закриття як аргумент функції під час виклику функції.
 2. Зробіть додаткову роботу з функцією.
 3. Функція запускає закриття.
 4. Функція повертає компілятор назад.

Приклад:

func getSumOf (масив: [Int], обробник: ((Int) -> недійсний)) {
        // крок 2
        вар сума: Int = 0
        для значення в масиві {
            сума + = значення
        }
        
        // крок 3
        обробник (сума)
    }
    
    func doSomething () {
        // установка 1
        self.getSumOf (масив: [16,756,442,6,23]) {[слабкий "] (сума) у
            друк (сума)
            // крок 4, закінчення виконання
        }
    }
// Він надрукує сумо всіх заданих номерів.

Тут ми просто назвали функцію із закриттям, яке виконується в кінці тіла функції.
Тож ми не уникаємо виконання закриття. По мірі виконання кроку 4 закриття не буде існувати в пам'яті.

2. Закриття @cacacaping:

Передаючи закриття як аргумент функції, закриття зберігається, щоб виконати пізніше, і тіло функції буде виконано, повертає компілятор назад. По закінченні виконання обсяг пройденого закриття існує і існує в пам'яті, поки завершення не завершиться.
 Існує кілька способів уникнути закриття:

  • Зберігання: Коли вам потрібно зберегти закриття у сховищі, яке існує в пам'яті, минуле функції виклику виконується і повертає компілятор назад. (Як і чекати відповіді API)
  • Асинхронне виконання: Коли ви виконуєте закриття асинхронно на черзі відправки, черга буде зберігати закриття в пам'яті для вас, яке буде використовуватись у майбутньому. У цьому випадку ви не маєте уявлення, коли закриття буде виконано.

Коли ви спробуєте скористатися закриттям із цим параметром, швидкий компілятор покаже помилку.

Життєвий цикл закриття @escaping:
1. Передайте закриття як аргумент функції під час виклику функції.
2. Зробіть додаткову роботу у функції.
3. Функція виконує закриття асинхронно або зберігається.
4. Функція повертає компілятор назад.

Приклад 1 (Зберігання):

var complitionHandler: ((Int) -> void)?
    func getSumOf (масив: [Int], обробник: @escaping ((Int) -> void)) {
        // крок 2
       // тут я берусь за цикл, наприклад, в реальному випадку це буде щось інше, як виклик API
       вар сума: Int = 0
        для значення в масиві {
            сума + = значення
        }
// крок 3
        self.complitionHandler = обробник
    }
    
    func doSomething () {
        // установка 1
        self.getSumOf (масив: [16,756,442,6,23]) {[слабкий "] (сума) у
            друк (сума)
            // крок 4, закінчення виконання
        }
    }
// Тут ми зберігаємо закриття для подальшого використання.
// Він надрукує сумо всі передані номери.

Приклад 2 (Асинхронне виконання):

func getSumOf (масив: [Int], обробник: @escaping ((Int) -> void)) {
        // крок 2
        вар сума: Int = 0
        для значення в масиві {
            сума + = значення
        }
        // крок 3
        Globals.delay (0,3, закриття: {
            обробник (сума)
        })
    }
    
    func doSomething () {
        // установка 1
        self.getSumOf (масив: [16,756,442,6,23]) {[слабкий "] (сума) у
            друк (сума)
            // крок 4, закінчення виконання
        }
    }
// Тут ми викликаємо закриття із затримкою 0,3 секунди
// Він надрукує сумо всі передані номери.

Ось ми зі значенням атрибута @escaping. Отже, коли вам потрібно уникнути виконання атрибута закриття, використовуйте @escaping атрибут у Swift 3. Вищеописана помилка компілятора зникне після того, як закриття як уникнене, використовуючи атрибут @escaping.

Чому вони зробили @nonescaping за замовчуванням?

Існує багато різних переваг, як зробити не втечу, як за замовчуванням. Найважливіші переваги - це ефективність роботи та оптимізація коду компілятором, оскільки якщо компілятор знає, що закриття не виходить, він подбає про розподіл пам'яті для закриття.

І ще один: ми можемо без проблем використовувати себе при незахищеному закритті, тому що закриття виконується до того, як функція повернеться, тож впевненість у собі буде там. Нам не потрібно використовувати слабку самості, це додаткова особливість .

У Swift 3 закриття не забуваються за замовчуванням, можна використовувати @escaping, якщо не те, що ми хочемо. Закриття, що не ухиляється, викликає виконання, перш ніж функція повернеться.
Завжди пам’ятайте, що під час використання застібки використовуйте слабке «я».

Дякуємо за прочитане, будь ласка, натисніть на рекомендацію, якщо сподобалась ця колекція this. Питання? Залиште їх у коментарі.