iOSエンジニアのつぶやき

毎朝8:30に iOS 関連の技術について1つぶやいています。まれに釣りについてつぶやく可能性があります。

【Swift】ClosureのCapture List再入門

Capture Listとは?

キャプチャリストは、よくClosure内で強参照によるインスタンスを保持を防ぐ下記のようなもので、Closure内で、ある値のキャプチャ方法を指定する役割があります。

let hoge = {[weak self] in
    self.hoge()
}

キャプチャ方法

キャプチャ方法は主に下記の3つがありますが、最初の2つがインスタンスを弱参照するキャプチャ方法になります。

[weak xxx]

[weak xxx]は対象となるオブジェクトを弱参照でアクセスすることを指定します。つまりアクセスする際にオブジェクトのインスタンスが解放されている可能性があるので、値はオプショナルになります。これは非同期処理のコールバックなんかでよく使いますよね。

let hoge = {[weak self] in
    self?.hoge()
}

[unowned xxx]

[unowned xxx][weak xxx]と同様に対象となるオブジェクトを弱参照でアクセスすることを指定します。weakとの違いは、オブジェクトを暗黙的にアンラップすることです。つまりインスタンスが解放されている場合に[unowned xxx]でキャプチャしたオブジェクトにアクセスするクラッシュします。ちなみにselfをキャプチャする場合には、明示的にselfを記述する必要がなくなります。

let hoge = {[weak self] in
    self.hoge()
}
let hoge = {[weak self] in
    hoge() // self.hoge
}

[xxx]

[xxx]は前述した二つとは異なり強参照でキャプチャされ、暗黙的にオブジェクトを参照することができます。

let hoge = {[self] in
    hoge() // self.hoge
}

余談

Capture List に追加されたオブジェクトは基本的にletに相当するImmutableなので、インスタンスの情報を書き換えるようなことはできません。

var singer = Singer()
let hoge = {[singer] in
    singer = Singer() // Cannot assign to value: 'singer' is an immutable capture
}

また、複数のオブジェクトをweakunownedとしてキャプチャしたい場合に下記のように書きたくなりますが、この場合2番目以降のオブジェクトは強参照されています。

let singer = Singer()
let singer2 = Singer()
let hoge = {[weak singer, singer2] in

}

どちらも弱参照にしたい場合には下記のように記述する必要があります。

let singer = Singer()
let singer2 = Singer()
let hoge = {[weak singer, weak singer2] in

}

参考

www.hackingwithswift.com

docs.swift.org

その他の記事

yamato8010.hatenablog.com

yamato8010.hatenablog.com

yamato8010.hatenablog.com