よく知らなかったのですが、調べてみたら積極的に使っていこうという気になりました。
使用例
関数の引数で渡すクロージャにattributeとして付けます。
func action(@noescape closure: () -> ()) {
closure()
}
@noescape
を付けたクロージャに保証されること
- クロージャはどこへも保持されない
- クロージャは非同期的に後から実行されることはない
つまり、
クロージャの生存期間が関数よりも短い
ことを保証することになります。
よって、クロージャを渡した先で
- クロージャをインスタンス変数などとして保持
- クロージャを非同期的に後で実行
などする場合にはクロージャの生存期間が関数よりも延びてしまうので @noescape
を付けることができません。
いいこと
クロージャ内で self.
を書かなくてよくなります。
more importantly disables the “self.” requirement in closure arguments.
(リリースノートより)
以下のような理由からではないかと思われます。
-
self.
の記述はクロージャの生存が終わるまではselfが開放されないことを明示するためのもの(たぶん) -
@noescape
が付いたクロージャは生存がすぐに終わる - クロージャの生存が終わってもselfは必ず存在する
- つまり、
self.
を書いてselfが開放されないことを明示する必要がない
self.
を書く必要がないということは [weak self]
や [unowned self]
について考える必要がない、つまり selfについての循環参照を考える必要がなくなる ということです!
@noescape
なしの例
func action(closure: () -> ()) {
closure()
}
class A {
var count = 0
func countAfterAction() {
action {
self.count++ // ここ
}
}
}
@noescape
ありの例
func action(@noescape closure: () -> ()) {
closure()
}
class A {
var count = 0
func countAfterAction() {
action {
count++ // ここ
}
}
}
またパフォーマンスが良くなる効果もあるようです。
This enables some minor performance optimizations
(リリースノートより)
結論
@noescape
を付けられる場合は @noescape
を付けていきたい。
- クロージャ内で
self.
を書く必要がなくなる - つまり、selfの循環参照の問題を気にしなくてよくなる
- パフォーマンスが良くなる
(おまけ) noescapeの意味
- 生き延びない (escapeしない) という意味みたいです。
This indicates that the parameter is only ever called (or passed as an @noescape parameter in a call), which means that it cannot outlive the lifetime of the call.
(リリースノートより)
環境
Apple Swift version 2.1 (swiftlang-700.1.101.6 clang-700.1.76)
Target: x86_64-apple-darwin14.5.0