Automatic Reference Counting

シェアする

Arc

Swift言語では、Objective-Cと同様Automatic Reference Counting(ARC)を使用してメモリが管理されています。

大体の場合、何も考えなくてもARCが正しくメモリを解放してくれますが、場合によっては参照カウントを意識して、問題が起こらないように注意深くコーディングしないといけない場面もあります。

ここではARCの原理から、特有の問題点である循環参照によるメモリリークが発生する原因、その回避方法などを説明します。

ARCの原理

ARCの原理はシンプルです。例えば以下のような簡単なクラスを考えます。

Personインスタンスを生成し、ref1、ref2、ref3に代入した後、順番にnilに設定していくと、最後の参照がnilに設定されたタイミングでdeinitが呼び出され、メモリが解放されることがわかります。

Swiftでは通常変数への代入によって参照カウントが増えていきます。参照数が増える参照を「強参照」と呼びます。

なおOptional型は強参照(そして弱参照にも)関係ありませんのでご注意ください。

ARCの問題: 循環参照

インスタンスが互いに強参照している場合にARCでメモリが解放できない状況が発生します。例えば以下の2つのクラスを考えます。

それぞれ互いのインスタンスを強参照しているため、参照カウントが0にならずどちらのインスタンスも解放されない状態が発生します。

循環参照をweak参照で解決する

循環参照を解消する方法はもちろん準備されています。その方法の一つ目はweak参照を使用することです。WeakApartmentクラスは「weak var tenant」と頭にweakをつけてインスタンスを参照していることに注目してください。

weak参照は参照カウントが増えない参照なのです。

WeakApartmentからはweak参照が使われているのでうまく解放することができます。ただしweak参照はOptionalなので使用する際にunwrapする必要があります。

循環参照をunowned参照で解決する

weakと似たunownedを使うこともできます。

unownedは非Optionalである代わりにインスタンス解放時にnilになりません。絶対にnilにならない場合に使用する必要があります。

ハマりやすいClosureからの循環参照

循環参照のバリエーションとしてClosureを使用する際、無意識のうちに循環参照状態になってしまうというものがあります。

インスタンスのプロパティとしてClosureを強参照し、Closureの処理内からselfでインスタンスを強参照すると循環参照が発生します。

この場合も通常の循環参照を解消する場合と同様に、weak/unowned参照を使って問題を解決することができます。

Closureがプロパティではない場合は問題ありません。

UIAlertControllerの表示処理って?

Closureを積極的に使うことはあまり無いとしても、UIKitを使っていると至る所で気にしないといけない部分がでてきます。例えばUIAlertControllerを使ってアラートを表示し、ボタンが押された場合の処理を行う箇所もClosureです。

上記の例の場合、alertはローカル変数として保持されているため循環参照は発生しません。alertをプロパティとして保持しない場合はweak selfでキャプチャしなおす必要はないのです。

ARCのまとめ

循環参照が発生するとメモリリークが発生する可能性があるので要注意です。ただしここで問題になるのはあくまで循環参照が発生する場合なので、例えばViewController間で引数オブジェクトを引き回す場合は問題ありません(循環参照しているわけではないので)。

またClosure内でselfを使う場合循環参照が発生しがちなので注意が必要です。同じようなパターンとしてdelegateを使って処理を以上するパターンもあります。

参考

スポンサーリンク
レクタングル(大)広告
レクタングル(大)広告

シェアする

フォローする