bridge系のキャスト

よく忘れてしまうので…


何がカウンタ方式か
ARC obj-cでも非ARC obj-cでもCF系(CoreFoundation系)でも全部カウンタ方式。プログラマが管理文を書くか書かない(コンパイラが書く?)かの違いはある。


カウンタはどこで持つか
2つの変数が同じインスタンスを参照している時カウンタはいくつか?
1つ。


__bridge系って何?
id系とCF系のキャストの箇所でコンパイラがretainとreleaseをどう書くかを指定するもの。
__bridge
__bridge_retained
__bridge_transfer
の3つ。
何をどう使ってもretainとreleaseがきちんと数を合わせて実行されてれば間違いではないと思いますが、3種類あるのは、人が見てわかりやすいとか、下で書くような管理責任をどうしたいのかを表すのには便利かと思います。


オーナーシップについて
オーナーシップという言葉で説明してあるものがかなりあります。もしよくわからない場合は、一旦retain releaseの追加という観点で理解してから、再度オーナーシップについて考えるのがおすすめです。


それぞれのパターンでキャストして代入するとこうなります。

__bridgeによるCF系からid系
id系 = (__bridge id系)CF系
id系がARC管理下に入ることによりカウンタ+1。ただし__weakであれば増加処理はなし。
キャスト後もCF系で管理したいときにおすすめ。id系が消えたあともCF系を使いたい時など。

__bridgeによるid系からCF系
CF系 = (__bridge CF系)id系
カウンタ変わらず
引き続きid系による(自動)管理をしたいときにおすすめ。キャスト後のCF系は管理しないことが前程だが一応管理命令は実行出来る。

__bridge_retainedによるid系からCF系
CF系 = (__bridge_retained CF系)id系
CF系がretainされるので+1
キャスト後のCF系で管理したいときにおすすめ。
id系は引き続き管理されている。

__bridge_transferによるCF系からid系
id系 = (__bridge_transfer id系)CF系
CF系がreleaseされることにより-1。キャスト後のCF系は管理しないことが前程。
id系がARC管理下に入ることによりカウンタ+1。ただし__weakであれば増加処理はなし(実際には__weakにはやらないでしょうが)。
結果プラマイ0 (__weakなら-1)
releaseの-1されるのはひとまとまりの実行文が実行された後。
結果がプラマイ0になることが多いので、(__bridge_retainedにあわせて)__bridge_releasedというネーミングにはならないと思われる
CF系からid系に管理を移したいときにおすすめ。


説明での言葉の選び方
オーナーシップの移動という表現がある。
①__bridgeではオーナーシップは移動しませんと表現しているものがよくあるが、CF系からid系へのキャストではid系の方はは当然ARCの管理下に置かれるので「両方によって所有(あるいは管理)されている」といったほうがわかりやすい(人がいる)かもしれない。
②__bridge_retainedではid系からCF系に移動すると思ってしまいがちであるが、これも元のid系は引き続きARCの管理下に置かれている。なのでこれも「両方によって所有(あるいは管理)されている」と言ったほうがいいかもしれない。
③__bridgeによるid系からCF系は文字通り「移動しません」あるいは「変化しません」でいいと思う。
④__bridge_transferによるCF系からid系へのキャストも「移動」でいいと思う。

「オーナーシップ」が表現しているものが「所有」ではなく「プログラマが管理する責任」だとすると①のパターンを「移動しません」と言ってもいいような気がするが、今度は④の「移動」が成り立たなくなるので困ったもんである(移動先でプログラマが管理する責任があることになるので)。「移動されたことにより責任から解放される」だとOKか。

この様にネーミングは、カウンタ管理の原理よりもプログラマの作業量による影響が強い。学習時には経験したことがなく作業量はわからないことが多いのでニュアンスがわからず惑わされる。


ちょっと違う観点から見てみる
私が理解しやすい考え方を書いてみる。
・それまで1つの変数からアクセスしていたインスタンスがキャストによって2つの変数(id系とCF系)からアクセス出来るようになる。
・キャスト後は、id系の方からはARCによって、+1している状態である。(__weak除く)
・CF系の方からは+1しているかしていないかを指定出来る。CF系の方からは+1しているとはCF系からreleaseする必要(ほかの言葉では予定、方針など)があるということ。
・キャスト後CF系の方から+1している状態となるCF→idへのキャスト、__bridge
・キャスト後CF系の方から+1している状態となるid→CFへのキャスト、__bridge_retained
・キャスト後CF系の方から+1していない状態となるCF→idへのキャスト、__bridge_transfer
・キャスト後CF系の方から+1していない状態となるid→CFへのキャスト、__bridge
となる。

コメント

このブログの人気の投稿

Swiftのコンパイルエラー寄せ集め

Swift2.2からSwift3.0への変換を行ってみて

AVAudioSession細かいことまとめ(late 2014)