lazy var の遅延参照?という面白い動き

  • 15
    Like
  • 6
    Comment

昨日とても不可解なバグがあったため色々試してみたが、最終的にはここまでは落とし込めたので、この動作を共有するとともになぜこのようなことが発生しているのかを教えていただける親切な方々がいればと願います。

まずは下記のコードを Playground とかで見てみましょう

struct Data {

    var int = 1

    mutating func increase(completion: (Int) -> Void) {
        self.int += 1
        completion(self.int)
    }

}

class Manager {

    var data = Data()

    var int: Int {
        return self.data.int
    }

    func increase() {
        self.data.increase { (i) in
            print(i)
            print(self.int)
        }
    }

}

let manager = Manager()
manager.increase()

さてこれを実行した場合の出力はどうでしょうかな?多分みなさんわかると思いますが、1 行目と 2 行目はともに 2 です。

さて、class Managerdatavar から lazy var、つまり lazy var data = Data() に直すと、果たして答えはどうでしょう?

実際やってみればすぐわかると思いますが、今度は 1 行目は前と同じ 2 で出力されるが、2 行目は 1 、つまり data が書き換えられる前の数値が出力されるのです。

もちろん manager.increase() の後にもう一回 print(manager.int) で見てみるとちゃんと書き換えられた後の 2 で出力されるのですが、値型で確実にデータの書き換えの同期が要求される場面では lazy は使わないほうがよさそうですね。(参照型は「参照先」である値が変わるわけではないので大丈夫かとは思いますが)

ところでこれはなぜでしょうか?🤔