Edited at

lazyプロパティ内でstaticメソッドを使用すると、2回目以降のアクセスでも処理が走る場合がある


2019/07/09 追記

@nukka123 さんのコメントより、Swiftのlazyプロパティという仕様どんな処理を呼ぼうが異なるスレッドからアクセスすれば初期化処理が1回に止まる保証はないことが判明してます。

https://qiita.com/m-yamada1992/items/d77adc52b75f6d44c3f6#comment-f24b8fc4241d8b918ce3


実行環境

Xcode 10.2.1

Swift 5



ViewController.swift

class ViewController: UIViewController {

private lazy var label: UILabel = {
return ViewController.createLabel()
}()

init() {
super.init(nibName: nil, bundle: nil)
self.addSubview(label)
}

func setup(text: String) {
label.text = text
}

static func createLabel() {
let label = UILabel()
return label
}
}


init() で初回のアクセスをしたタイミングでlabelプロパティが生成され、2回目以降にsetup(text:)メソッドでアクセスした際には生成済みのインスタンスにアクセスされることを想定していた。

が、ViewController.createLabel()が2回目以降も走っていることが発覚。


解決策


lazyプロパティ内の定義をいずれかに変更

要は、staticメソッドさえ使わなければ想定通りの遅延初期化プロパティな挙動をする。


直接生成

    private lazy var label: UILabel = {

let label = UILabel()
return label
}()


インスタンスメソッドを用いて生成

    private lazy var label: UILabel = {

return self.createLabel()
}()

static func createLabel() {
let label = UILabel()
return label
}


lazyではなくlet宣言にする

    private let label: UILabel

init() {
self.label = ViewController.createLabel()

super.init(nibName: nil, bundle: nil)
self.addSubview(label)
}

static func createLabel() {
let label = UILabel()
return label
}