Обновление закрытий для Swift 3 – @ escaping

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

( EDIT : на самом деле, @scaping должно быть добавлено после 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 } 

Любая помощь очень ценится!

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

До Swift 3 атрибуты закрытия @autoclosure и @noescape были атрибутами параметра закрытия, но теперь являются атрибутами типа параметра; см. следующее принятое эволюционное предложение Swift:

  • SE-0049: Move @noescape и @autoclosure должны быть атрибутами типа

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

  • SE-0103: сделать неэксклюзивное закрытие по умолчанию

Эти предложения теперь реализованы на бета-стадии Xcode 8 (см. Примечания к выпуску для Xcode 8 beta 6 ; для входа в систему требуется учетная запись для входа)

Новое в Xcode 8 beta 6 – Swift Компилятор: Swift Language

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

Новое в Xcode 8 beta – Swift и Apple LLVM-компиляторы: Swift Language

@noescape и @autoclosure теперь должны быть записаны перед типом параметра, а не перед именем параметра. [SE-0049]

Следовательно, вы используете атрибут @escaping значения по умолчанию, следующим образом; применяется к типу параметра закрытия, а не самому параметру

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

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

@Cristi Băluţă: «Что делает побег? Никогда не видел эти ключевые слова перед автоматическим преобразованием swift3 …»

См., Например, ссылку на предложение эволюции SE-0103 выше (а также цитированный текст из бета-версий 6): ранее параметры закрытия были экранированы по умолчанию (отсюда нет необходимости в наличии явной annotations для экранирования), но теперь по умолчанию они не ускользают. Следовательно, добавление @escaping позволяет явно аннотировать, что параметр закрытия может уйти (вопреки его поведению по умолчанию). Это также объясняет, почему @noescape теперь устарел (нет необходимости комментировать поведение по умолчанию).

Для объяснения того, что означает, что параметр закрытия экранируется, я цитирую атрибуты языка – атрибуты :

Msgstr “Применить этот атрибут к типу параметра в объявлении метода или функции, чтобы указать, что значение параметра может быть сохранено для последующего выполнения. Это означает, что это значение позволяет пережить время жизни вызова.”

@noescape

Из xcode 8 бета 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 } } 

Это скомпилирует ok (явно пишу @escaping )

 class MyClass { var myClosure: (() -> ())? func doSomething(finishBlock: @escaping () -> ()) { myClosure = finishBlock } } 

Преимущества @noescape :

  • Компилятор может оптимизировать ваш код для повышения производительности.
  • Компилятор может позаботиться об управлении памятью
  • Нет необходимости использовать слабую ссылку на себя в закрытии

Для получения дополнительной информации ознакомьтесь с: Сделайте неэксклюзивное закрытие по умолчанию

  • Храните закрытие в виде переменной в Swift
  • Что такое «закрытие» в .NET?
  • Давайте будем гением компьютера.