🔖
【Swift】@_implicitSelfCaptureについて
@_implicitSelfCaptureとは
escaping
属性が指定されているクロージャ内でself
を参照し、そのself
が参照型である場合は基本的にself
を付けて明示的にキャプチャを行わなければなりません。
この制約を排除できるのが@_implicitSelfCapture
です。
以下のコードでは、escaping
属性が指定されているクロージャ内でself
を参照していますが、明示的なキャプチャが行われていないため、コンパイルエラーが発生しています。
var someAction: () -> Void = {}
func setAction(_ action: @escaping () -> Void) {
someAction = action
}
class Sample {
var value = 0
func action() {
setAction {
value = 777 // 【Error】
}
}
}
// ※ メモリリークに関しては無視してください。
setAction
の引数に@_implicitSelfCapture
を付与すると、上記のエラーは発生しなくなります。
var someAction: () -> Void = {}
func setAction(@_implicitSelfCapture _ action: @escaping () -> Void) { // 変更
someAction = action
}
class Sample {
var value = 0
func action() {
setAction {
value = 777
}
}
}
// ※ メモリリークに関しては無視してください。
@_implicitSelfCaptureはどこで使われているのか
@_implicitSelfCapture
はTask
のイニシャライザの引数operation
などに対して付けられています。
そのためTask
内では、明示的なキャプチャを示すためのself
を記入する必要はありません。
@MainActor
final class ViewModel: ObservableObject {
@Published private(set) var num = 0
func action() {
Task {
try? await Task.sleep(for: .seconds(3))
num += 1
}
}
}
※ 本題から逸れますが、operationがViewModelインスタンスを強参照するため、解放遅延が生じる可能性があります。
参考
Discussion