Оновлення закриття до Swift 3 - @escaping


75

Я оновив свій код до Xcode 8.0 beta 6, але я застряг у тому, що, здається, стосується нового типового закриття, що не виходить. У наведеному нижче коді Xcode пропонує додати @escapingйого completion:в перший рядок коду нижче, але це все одно не компілюється і йде по колу. *

( EDIT : Насправді @escaping слід додати після completion: , як пропонує Xcode. Оповіщення все одно може відображатися, але очищення та компіляція видалять його.) * Як цей код слід переписати / виправити для роботи в оновленому Swift 3 ? Я подивився новий посібник, але не зміг знайти належні зразки коду.

func doSomething(withParameter parameter: Int, completion: () -> ()) {
    // Does something

    callSomeOtherFunc(withCompletion: completion)
  }

// Calling the method and execute closure 
doSomething(withParameter: 2) {
  // do things in closure
}

Будь-яка допомога дуже вдячна!

Відповіді:


58

Swift 3: атрибути параметра закриття тепер застосовуються до типу параметра , а не до самого параметра

До Swift 3 атрибути закриття @autoclosureі @noescapeраніше були атрибутами параметра закриття , але тепер є атрибутами типу параметра ; див. наступну прийняту пропозицію Swift evolution:

Ваше конкретне запитання стосується атрибута типу параметра @escaping(для якого застосовується те саме нове правило), як описано у прийнятій пропозиції еволюції Swift, щоб дозволити параметрам закриття за замовчуванням не екранувати:

Тепер ці пропозиції реалізовані на бета-стадії Xcode 8 (див. Примітки до випуску для Xcode 8 beta 6 ; для доступу потрібен вхід в обліковий запис розробника)

Нове у Xcode 8 beta 6 - Swift Compiler: Swift Language

Параметри закриття за замовчуванням не екрануються, а не явно анотовані @noescape. Використовуйте @escapingдля позначення того, що параметр закриття може вийти. @autoclosure(escaping)тепер пишеться як @autoclosure @escaping. Анотації @noescapeта @autoclosure(escaping)застаріли. (SE-0103)

...

Нове у бета-версії Xcode 8 - компілятори Swift та Apple LLVM: мова Swift

Тепер атрибути @noescapeand @autoclosureслід писати перед типом параметра, а не перед іменем параметра. [SE-0049]

Отже, ви використовуєте @escapingатрибут не за замовчуванням наступним чином; застосовується до типу параметра закриття, а не до самого параметра

func doSomething(withParameter parameter: Int, completion: @escaping () -> ()) {
    // ...
}

(Включаючи мою відповідь на запитання в прихильному коментарі нижче, оскільки коментарі не є постійними даними про SO)

@Cristi Băluță: "Що робить втеча? Ніколи не бачив цих ключових слів до автоматичного перетворення swift3 ..."

Див., Наприклад, посилання на пропозицію щодо еволюції SE-0103 вище (а також наведений текст із приміток до випуску бета-версії 6): раніше параметри закриття за замовчуванням сходили (отже, немає необхідності існувати явна анотація для екранування), але тепер за замовчуванням замість цього не виходять. Звідси додано, @escapingщоб явно анотувати, що параметр закриття може вийти (всупереч поведінці за замовчуванням). Це також пояснює, чому @noescapeзараз застаріла (не потрібно коментувати поведінку за замовчуванням).

Щоб пояснити, що це означає, що параметр закриття витікає, я цитую посилання на мову - атрибути :

"Застосуйте цей атрибут до типу параметра в декларації методу або функції, щоб вказати, що значення параметра можна зберегти для подальшого виконання. Це означає, що це значення може пережити термін дії виклику."


Дякую за ретельну відповідь dfri. Я насправді додав @escaping у потрібному місці перед параметром, я просто помітив свою помилку, вказуючи це на опис. Xcode все одно скаржиться, як я описав, але все одно очищення та компіляція остаточно видаляє попередження.
нетиповий

@nontomatic радий допомогти.
dfrib

7
Що робить втеча? Ніколи не бачив цих ключових слів до автоматичного перетворення swift3, і я не думаю, що я щось втратив.
Крісті Балуша,

@ CristiBăluță див., Наприклад, посилання на пропозицію щодо еволюції SE-0103 вище (а також цитований текст із приміток до випуску бета-версії 6): раніше параметри закриття за замовчуванням відходили (отже, немає необхідності в анотації, що вони втікають), але зараз замість цього не втікають. Звідси додано, @escapingщоб явно анотувати, що параметр close може втекти (всупереч поведінці за замовчуванням). Це також пояснює, чому @noescapeзаборонено (не потрібно анотувати поведінку за замовчуванням).
dfrib

3
@ SagarR.Kothari І питання, і відповідь ґрунтуються на тому, що ми знаємо різницю між закриттям і непрохідним закриттям, отже, мій попередній коментар до CristiBăluță (відповіді, чому це ключове слово зараз існує). Для пояснення того, що він робить, я цитую lang. посилання: "Застосувати цей атрибут до типу параметра в методі або декларації функції, щоб вказати, що значення параметра можна зберегти для подальшого виконання. Це означає, що значення має змогу пережити термін дії виклику." .
dfrib

23

@noescape

З xcode 8 beta 6 @noescapeє типовим. До цього @escapingбув типовим. Будь-хто, хто оновлюється до швидкої версії 3.0 з попередніх версій, може зіткнутися з цією помилкою.

Ви не можете зберігати @noescapeзакриття всередині змінної. Оскільки, якщо ви можете зберегти закриття всередині змінної, ви можете виконати закриття з будь-якого місця вашого коду. Але @noescapeстверджує, що параметр закриття не може вийти з тіла функції.

Це дасть помилку компілятора в Xcode 8

class MyClass {

    var myClosure: (() -> ())?

    func doSomething(finishBlock: () -> ()) {
        myClosure = finishBlock    // ‼️ Error: Assigning non-escaping parameter 'finishBlock' to an @escaping closure
    }
}

Це скомпілює нормально (явно напишіть @escaping)

class MyClass {

    var myClosure: (() -> ())?

    func doSomething(finishBlock: @escaping () -> ()) {
        myClosure = finishBlock
    }
}

Переваги @noescape:

  • Компілятор може оптимізувати ваш код для кращої продуктивності
  • Компілятор може подбати про управління пам'яттю
  • Немає необхідності використовувати слабке посилання на себе при закритті


Для отримання детальної інформації перевірте: Замовчуйте не закриваючі закриття

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.