2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

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

Last updated at Posted at 2019-07-08

2019/07/09 追記

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

実行環境

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
    }
2
2
3

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
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?