【Swift】Computed property じゃないのに「'lazy' cannot be used on a computed property」と言われた

はじめに

表題のエラーに遭遇したので、原因と対応を記載していきます。

何が起こった?

まずは、下記のスクショを見てみましょう。

コードとしては下記のような感じです。

final class Foo {
    private lazy var bar: Int = 1
}

表題の通り、 Computed property ではないのに 'lazy' cannot be used on a computed property というコンパイルエラーが出ています。
実行環境は下記のとおりです。

  • Xcode 16.2 (16C5032a)
    • with Swift 6.0.3.1.10

なぜ?

実は、上記のスクショは著者によって意図的な切り取り方がされています。
もう少し全体を見てみましょう。

そうです。今回エラーが出ているのは Observation framework を使って、 @Observable マクロを付与しているクラスになります。
全体のコードは下記です。

import Observation

@Observable
final class Foo {
    private lazy var bar: Int = 1
}

原因

@Observable マクロをつけたクラスのプロパティは、 @ObservationIgnored を付与しない限り @ObservationTracked マクロが自動的に付与されます。
@Observable なクラスでは @ObservationTracked プロパティがついたプロパティが監視対象になりますが、監視対象のプロパティは lazy が許容されていないようです。

@Observable マクロを展開した様子
さらに @ObservationTracked を展開した様子

エラーメッセージが適切ではないので初見では何が起こっているのか非常に分かりづらいですね、、

対応

対応としては、下記のいずれかになるかと思います。

  • @ObservationIgnored を付与して監視対象から外す
  • そもそも lazy を消す

前者の対応であれば lazy var を定義可能です。

補足

本記事の執筆時点で GitHub の Swift のリポジトリに下記の issue が open されています。

github.com

エラーメッセージが適切じゃないので変更しようという提案がされているようなので、いつか対応されるかもしれませんね。

おわりに

iOS 17 以降で利用できる Observation framework も少しずつ利用されるようになってきているかなと思いますが、
皆さんも Observation を使っていることをついつい忘れて、通常のクラスのように lazy を定義してこのエラーに遭遇することが出てくることがあるかもしれません。
その時は焦らず @Observable 付きのクラスでないかを確認していただければと思います。