【Swift】初心者が実務のソースコードから学ぶ『lazy』プロパティ

公開日: 

はじめに

この記事では、『見たことはあるけど、説明はできない。』でおなじみ、lazyプロパティについて解説します。 後半では、実務で実際に使われていたコードも紹介しています。

https://qiita.com/shiz/items/782979bd8a539c9d2291

lazy プロパティとは

lazy プロパティは簡単にいうと『呼ばれるまで初期化処理が走らない』プロパティです。通常のプロパティはオブジェクトのインスタンス生成と同時に初期化されます。ですが、lazy プロパティはそのプロパティが呼ばれるまで初期化処理が走りません。そして、1 度初期化処理が走るとメモリに値が保存されるため、再度処理は走りません。使い所としては、

  • 初期値がインスタンス生成後の状態に依存している
  • 初期化処理が重いので、使われるまでは初期化したくない

などの特徴を持つプロパティに使用し、上手く使うことで無駄な処理を避け、アプリのパフォーマンスを向上させることができます。

動作の確認

Playground で確認してみます。

playground
class Example {

    var normalProperty: Int = {
        print("通常のプロパティを生成します")
        return 1
    }()

    lazy var lazyProperty: Int = {
        print("lazyプロパティを生成します")
        return 1
    }()

}

let example = Example() // 通常のプロパティはここで初期化
print("通常のプロパティの値は\(example.normalProperty)です")
print("lazyプロパティの値は\(example.lazyProperty)です") // lazyプロパティは呼ばれた時に初めて初期化


// 結果
通常のプロパティを生成します
通常のプロパティの値は1です
lazyプロパティを生成します
lazyプロパティの値は1です

簡単なクラスを作って確認してみると確かに lazy プロパティはクラスのインスタンスが生成されたときではなく、呼ばれた時に初期化が走っています。なるほど、使い方次第では便利そう...

実務で実際に使われていた場面

で、実際にはどんな場面で使われてるんだ??

以下では実際に僕のインターン先にて lazy プロパティが使用されていた部分を紹介します。

使用例 ①: VC をプロパティにもつ

sample1-1.swift
private lazy var sampleVC: UIViewController = {
        let vc = SampleViewController()
        /* いろんな初期化処理 */
        return vc
    }()

このプロパティとして保持されている VC には以下の特徴があります。

  • インスタンス化が少し重い
  • 呼ばれない可能性もあり
  • 複数箇所で呼ばれる可能性あり

インスタンス化が重い・呼ばれない可能性もありというのは、まさに lazy プロパティの出番。呼ばれない可能性のある重いプロパティをわざわざ最初に初期化する必要はありません。

画面遷移の処理を書く場所でインスタンス化すれば実質同じことなのでは?

sample1-2.swift
/* 1箇所でしか呼ばれないならこれで良くね */
func transition() {
    let vc = ViewController()
    // vcの初期化処理

    // 画面遷移処理
}

と思ったのですが、今回は複数箇所でこのプロパティが呼ばれる可能性があるので各処理でインスタンス化するよりもまとめて初期化したい。そこで lazy プロパティを使うわけです。なるほど

使用例 ②: viewDidLayoutSubviews で使う

sample2.swift
private lazy var initViewDidLayoutSubviews: (() -> Void)? = {

        // UIパーツのframeを使う初期化処理

        return nil
    }()

この lazy プロパティは VC のライフサイクルのviewDidLayoutSubviewsの中で呼ばれています。

AutoLayout を使用した場合、パーツの frame の値が決まるのはviewWillAppearの後であるため、frame の値を使って、見た目を設定したい場合はviewDidLayoutSubviewsの中に書かなければいけません。

しかし、このviewDidLayoutSubviewsは何度も呼ばれる可能性があるため、普通に書いてしまうと何度も同じ処理が呼ばれてしまいます。なのでここで lazy の出番なんですね。なるほど

以上が、実務での使用例です。

最後に

『lazy』って『怠惰』みたいな意味らしいです。へぇ。

では、Bye