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

【Swift4.1】lazyプロパティの使い所

More than 1 year has passed since last update.

はじめに

Swiftを学び始めてしばらく経ちますが、
lazyプロパティをまだ上手く使いこなせていません。
そこで、具体的にどんなところで使うことが出来るのかをまとめてみました。

基礎

参照された時に初めて初期値が設定されるプロパティ

lazyなし
var defaultPrice = 100

class Item {
    var price: Int = defaultPrice
}

let item = Item()

defaultPrice = 200
print(item.price) // 100
lazyあり
var defaultPrice = 100

class Item {
    lazy var price: Int = defaultPrice
}

let item = Item()

defaultPrice = 200
print(item.price) // 200

defaultPrice = 300
print(item.price) // 200

ImplicitlyUnwrappedOptionalに似ているが、
lazyでは宣言時に値の初期値を決めておくことが出来る。

初期化タイミングに合わせて初期値を決定したい時

初期化時点で計算メソッドを呼び出したい時に使える。
該当プロパティのみのためであればクロージャでも代用可能。

var defaultPrice: Double = 100

class Item {
    // lazyがないとコンパイルエラー
    lazy var price: Double = applyTax(price: defaultPrice)

    func applyTax(price: Double) -> Double {
        return price * 1.08
    }
}

let item = Item()

print(item.price) // 108

複数のイニシャライザで呼び出していた処理を一箇所にしたい時

今まで適当に初期化してイニシャライザで設定していたのをまとめられる。

class CustomView: UIView {
    // Before : var subView = SubView()
    lazy var subView: SubView = setupSubView()

    override init(frame: CGRect) {
        super.init(frame: frame)
        // Before : 初期化時にSubView()してViewの設定をしていたメソッド
        // Before : setupSubView()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        // Before : 初期化時にSubView()してViewの設定をしていたメソッド
        // Before : setupSubView()
    }

    private func setupSubView() -> SubView {
        let view = SubView()
        view.frame = CGRect(...)
        return view
    }
}

特定のオブジェクトを生成する静的なメソッドを特定のタイミングでのみ呼び出したい時

ファクトリーメソッドを初期化時点で記述出来る。

class ViewController: UIViewController {
    lazy var actionButton: UIButton = ViewFactory.makeActionButton()

    func present(infoView: InfoView) {
        view.addSubview(infoView)
        infoView.frame = view.bounds.offsetBy(dx: 0, dy: view.bounds.height)
        infoView.present(animated: true)

        // ここで初めてActionButtonが生成される
        actionButton.center = view.center
        view.addSubview(actionButton)
    }
}

非オプショナルを求めるプロトコルのプロパティに後から値を入れたい時

参照時には値が初期化されるため、非オプショナルに対応出来る。

protocol ItemProtocol {
    var price: Double { get }
}

class Item: ItemProtocol {
    lazy var price: Double = getPrice()

    func getPrice() -> Double {
        return 100.0
    }
}

let item = Item()

print(item.price) // 100

注意

便利なlazyですが、
初期化タイミングが不明瞭なため思わぬバグを引き起こすことがあります。

私見ではありますが、
プロジェクト内での利用タイミングの統一やコメントでの補足等しておく必要はあるかと思います。

参考

http://hajihaji-lemon.com/smartphone/swift/lazy/
https://medium.com/@johnsundell/using-lazy-properties-in-swift-592c777e0052
http://www.ssktm.info/entry/2017/11/28/093046
https://www.slideshare.net/tomohirokumagai54/lazy-var-cocoakansai-cswift

negi0205
i-enter
「効果」をつねに提供します。スマホアプリ開発No.1の実績。最新のIoTに対応した開発も行います。
https://www.i-enter.co.jp/
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
ユーザーは見つかりませんでした