【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 }
また、複数のオブジェクトをweak
やunowned
としてキャプチャしたい場合に下記のように書きたくなりますが、この場合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 }