LoginSignup
93
62

More than 5 years have passed since last update.

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

Last updated at Posted at 2018-05-01

はじめに

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

93
62
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
93
62