属性
クロージャを関数や別のクロージャの引数として利用する場合にのみ有効な仕様として、属性があります。属性はクロージャに対して指定する追加情報です。
属性の指定方法
属性は、クロージャの型の前に@属性名を追加して指定します。
escaping属性
escaping属性は、関数に引数として渡されたクロージャが、関数のスコープ外で保持される可能性があることを示す属性です。
コンパイラはescaping属性の有無によって、クロージャがキャプチャを行う必要があるかを判別します。
クロージャが関数のスコープ外で保持されなければ、クロージャの実行は関数の実行中に限られるため、キャプチャは必要ありません。
一方、クロージャが関数のスコープ外で保持される可能性がある場合、つまりescaping属性が必要な場合は、クロージャの実行時まで関数のスコープの変数を保持する必要があるため、キャプチャが必要となります。指定しない場合はコンパイルエラーとなります。
var ary = [()->Void]()
func sam(arg: @escaping ()->Void){
//関数のスコープ外の配列に追加
//クロージャが関数外で保持されることになるので@escaping属性が必要
ary.append(arg)
}
sam {print("executed")}
sam {print("executed")}
ary.forEach { $0() }
//実行結果
//executed
//executed
escaping属性が指定されていないクロージャ
escaping属性が指定されていないクロージャは、関数のスコープ外で保持できません。したがって、クロージャの実行は関数のスコープ内で行われなければなりません。
func sam(arg: ()->Void){
arg()
arg()
}
sam{print("executed")}
//実行結果
//executed
//executed
上記はescaping属性が指定されていませんが、関数のスコープ内のみで実行されるためコンパイルエラーになりません。