Help us understand the problem. What is going on with this article?

[Swift] 一度だけ実行したい処理をクロージャでスマートに書く

More than 3 years have passed since last update.

はじめに

ViewControllerにおいて、viewWillAppearまたはviewDidLayoutSubviewsなどのタイミングで一度だけ実行したい処理をたまに書きたいことがあると思います。(viewDidLoadに記述できるのであればもちろんその方がスマートですが)

dispatch_once は使えない

GCDのdispatch_onceはマルチスレッドを考慮したシングルトン生成のパターンによく利用されますが、アドレスを指定した処理であるため静的に配置される変数(static変数)に対してしか正しく処理できません。(アプリケーション実行中に本当に一度だけ実行したいケースにしか利用できない)

言い換えると、今回のようなViewControllerが生成された後で一度だけ処理したい、というようなケースには対応できません。

シンプルに書くと

以下の様な処理になるでしょうか?

var isFirst = true // 最初の処理かどうか

override func viewWillAppear(animated: Bool) {
    super.viewWillAppear(animated)

    // 最初の処理だったら実行して、フラグ用の変数はfalseに落とす
    if isFirst {
        isFirst = false
        // 一度だけ実行したい処理
    }
}

シンプルではありますが、以下のような欠点があるように感じます。

  • 状態管理のための変数が追加されている。
  • 判定処理やフラグ更新処理のために、本質的な処理が埋もれがちになる。

アプリケーションの規模が小さければ大したことありませんが、大きくなってくると見過ごせない問題になってきます。

クロージャで書いてみる

いくぶん実験的ではありますが、以下のように書いてみました。

typealias ExecuteOnce = () -> ()

// 一度だけ引数にしていされたクロージャを実行するクロージャを返す関数
func executeOnce(execute: () -> ()) -> ExecuteOnce {
    var first = true
    return {
        if (first) {
            first = false
            execute()
        }
    }
}

class ViewController: UIViewController {

    // 一度だけ実行したい処理
    var someInitialize: ExecuteOnce = {}

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)

        // 処理を定義(selfキャプチャが不要であれば定数プロパティとして宣言可能)
        someInitialize = executeOnce { [unowned self] in
            // 一度だけ実行したい処理
        }
    }

    override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(animated)
        someInitialize() // 何度呼びだされても実行されるのは一度だけ
    }  
}

多少コード量は増えましたが、フラグ変数を追加することなく一度だけ処理することを実現できました。また、全体的に宣言的でスッキリとしたコードに出来たような気がします。

最後に

最初は、dipatch_onceのようなイメージでBool変数のアドレスを渡すような以下のコードを思いつきました。

executeOnce(&isFirst) {
    // 一度だけ実行したい処理
}

フラグ変数を自分で更新するよりはいくぶんスッキリしますが、フラグ変数を宣言する必要があるのは変わりません。

ということで、クロージャを活用した処理を考えてみたわけですが・・・他にスマートな方法をご存じの方がいましたら教えて下さい。

YusukeHosonuma
iOSテスト本とか書きました。Qiitaでなくブログに書くことも多いです。 📕 iOSアプリ開発自動テストの教科書 / iOSテスト全書 💻 iOS / Swift / Haskell / Go / Java / Ruby 🎤 https://speakerdeck.com/yusukehosonuma
http://blog.penginmura.tech/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした