Ответ 1
В Swift 3 все блокировки по умолчанию не выполняются
Нет, в Swift 3 аргументы функции закрытия (т.е. функциональные входы, которые являются самими функциями) по умолчанию не экранируются (согласно SE-0103). Например:
class A {
let n = 5
var bar : () -> Void = {}
func foo(_ closure: () -> Void) {
bar = closure // As closure is non-escaping, it is illegal to store it.
}
func baz() {
foo {
// no explict 'self.' required in order to capture n,
// as foo closure argument is non-escaping,
// therefore n is guaranteed to only be captured for the lifetime of foo(_:)
print(n)
}
}
}
Так как closure
в приведенном выше примере не является экранирующим, ему запрещено хранить или захватывать, тем самым ограничивая его время жизни на время жизни функции foo(_:)
. Это означает, что любые значения, которые он фиксирует, гарантированно не остаются захваченными после выхода функции - это означает, что вам не нужно беспокоиться о проблемах, которые могут возникнуть при захвате, например, о циклах сохранения.
Однако закрытое хранимое свойство (например, bar
в приведенном выше примере) по определению экранируется (было бы бессмысленно отмечать его @noescape
), поскольку его время жизни не ограничивается данной функцией - оно (и поэтому все его захваченные переменные) останется в памяти, пока данный экземпляр останется в памяти. Поэтому это может легко привести к таким проблемам, как сохранение циклов, поэтому вам нужно использовать явный self.
, чтобы сделать семантику захвата явной.
Фактически, примерный код вашего примера создаст цикл сохранения при вызове viewDidLoad()
, поскольку someClosure
сильно фиксирует self
и self
сильно ссылается на someClosure
, поскольку это хранимое свойство.
Конечно, одно место, где вы могли бы использовать атрибут @noescape
, - это замыкание, в котором есть локальная переменная в функции. Такое закрытие будет иметь прогнозируемое время жизни, если оно не хранится вне функции или не захвачено. Например:
class A {
let n = 5
func foo() {
let f : @noescape () -> Void = {
print(n)
}
f()
}
}
К сожалению, поскольку @noescape
удаляется в Swift 3, это будет невозможно (что интересно в Xcode 8 GM, это возможно, но дает предупреждение об устаревании). Как Jon Shier говорит, ему нужно ждать, пока он будет добавлен к языку, что может или не может произойти.