Go to list of users who liked
Share on X(Twitter)
Share on Facebook
More than 5 years have passed since last update.
はじめに
ViewControllerにおいて、viewWillAppearまたはviewDidLayoutSubviewsなどのタイミングで一度だけ実行したい処理をたまに書きたいことがあると思います。(viewDidLoadに記述できるのであればもちろんその方がスマートですが)
dispatch_once は使えない
GCDのdispatch_onceはマルチスレッドを考慮したシングルトン生成のパターンによく利用されますが、アドレスを指定した処理であるため静的に配置される変数(static変数)に対してしか正しく処理できません。(アプリケーション実行中に本当に一度だけ実行したいケースにしか利用できない)
言い換えると、今回のようなViewControllerが生成された後で一度だけ処理したい、というようなケースには対応できません。
シンプルに書くと
以下の様な処理になるでしょうか?
varisFirst=true// 最初の処理かどうかoverridefuncviewWillAppear(animated:Bool){super.viewWillAppear(animated)// 最初の処理だったら実行して、フラグ用の変数はfalseに落とすifisFirst{isFirst=false// 一度だけ実行したい処理}}シンプルではありますが、以下のような欠点があるように感じます。
- 状態管理のための変数が追加されている。
- 判定処理やフラグ更新処理のために、本質的な処理が埋もれがちになる。
アプリケーションの規模が小さければ大したことありませんが、大きくなってくると見過ごせない問題になってきます。
クロージャで書いてみる
いくぶん実験的ではありますが、以下のように書いてみました。
typealiasExecuteOnce=()->()// 一度だけ引数にしていされたクロージャを実行するクロージャを返す関数funcexecuteOnce(execute:()->())->ExecuteOnce{varfirst=truereturn{if(first){first=falseexecute()}}}classViewController:UIViewController{// 一度だけ実行したい処理varsomeInitialize:ExecuteOnce={}requiredinit?(coderaDecoder:NSCoder){super.init(coder:aDecoder)// 処理を定義(selfキャプチャが不要であれば定数プロパティとして宣言可能)someInitialize=executeOnce{[unownedself]in// 一度だけ実行したい処理}}overridefuncviewWillAppear(animated:Bool){super.viewWillAppear(animated)someInitialize()// 何度呼びだされても実行されるのは一度だけ}}多少コード量は増えましたが、フラグ変数を追加することなく一度だけ処理することを実現できました。また、全体的に宣言的でスッキリとしたコードに出来たような気がします。
最後に
最初は、dipatch_onceのようなイメージでBool変数のアドレスを渡すような以下のコードを思いつきました。
executeOnce(&isFirst){// 一度だけ実行したい処理}フラグ変数を自分で更新するよりはいくぶんスッキリしますが、フラグ変数を宣言する必要があるのは変わりません。
ということで、クロージャを活用した処理を考えてみたわけですが・・・他にスマートな方法をご存じの方がいましたら教えて下さい。
Register as a new user and use Qiita more conveniently
- You get articles that match your needs
- You can efficiently read back useful information
- You can use dark theme