【Swift】Timerの強参照が破棄できない時の対処法(deinit での破棄方法)

【Swift】Timerの強参照が破棄できない時の対処法(deinit での破棄方法)

iOSにて、Timerライフサイクルから破棄する事が不可能な場合において、deinitで破棄する方法を備忘録。
Timer はそれ自体を保持しているクラスをdelegateとして持つ事が多いと思います。
この場合循環参照になるので明示的に破棄しなければなりませんが、willDisappear などのライフサイクル系delegateを利用できない場合に、deinit にて破棄できるようにした参考例です。
 

Timer.scheduledTime関数 の使い方

Timer.scheduledTime関数 の基本的な使い方は下記にまとめましたので、ご参考ください。
【Swift】加算型Timer(ストップウォッチみたいな)の作り方 〜Timerの基本的な使い方〜
 

Timer の破棄タイミングがない状況

通常 ViewController などで Timer を利用するのであれば、willDisappear あたりのdeleageで破棄すれば良いかと思います。
ですが、こうしたライフサイクル系のdelegateが充実していないクラスや、複雑な処理を組んでおり deinit< タイミングでのみ破棄を行いたい場合などあるかと思います。

しかし、Timer が循環参照に陥っている限り、そのクラスの deinit は走りません。
したがって、

「複雑な処理を行なっているから、ViewControllerが破棄されるタイミングでTimerも破棄したいのにー!!!」

という願いが叶わなくなります。

コードで説明するとこんな感じです。

 

Timer を deinit で破棄する方法

上記の通り、原因は Timer の循環参照にあるので、これを回避すれば deinit は呼ばれるようになるわけです。

そこで Timer を保持するクラスを別途作成し、プロパティではそのクラスを持つ ようにします。
そうする事で、Timer保持クラス をプロパティで持つクラスは deinit が走るので、そのタイミングで Timer保持クラス が持つ Timer を破棄してあげれば良いわけです。

コードで書くとこんな感じです。

こちらの構成であれば、クラスの deinit を起点に Timer を破棄する事ができると思います。
破棄タイミングに困ったら、こちらをお試しくださいまし!
 

参考ドキュメント

公式RunLoopドキュメント
公式RunLoop.Modeドキュメント
公式ThreadProgramingGuide