ProgrammingiOS開発者

Swiftにおけるプロパティオブザーバーはどのように機能し、なぜ必要なのですか?

Hintsage AIアシスタントで面接を突破

回答。

Swiftのプロパティオブザーバーは、プロパティの値の変更に反応することができます。この概念は、データの変更をより透明に管理し、変更時のロジックを自動化するためにSwiftとともに導入されました。

背景:

Swift以前は、このような動作は手動でsetterや特別なメソッドを使って実装されていました。Swiftでは、オブザーバーは言語の標準的なツールとして登場しました。

問題:

開発者はプロパティの変更時点をキャッチすることが重要であり、たとえばUIの更新やデータのバリデーションのために必要です。オブザーバーがなければ、コードはより冗長になり、可読性が低下します。

解決策:

Swiftでは、2つの主要なオブザーバーが利用可能です。

  • willSetは値の変更前に呼び出されます。
  • didSetは新しい値の代入後に呼び出されます。

オブザーバーは、ストレージプロパティには追加できますが、lazyプロパティや計算プロパティには追加できません。

コード例:

class Temperature { var celsius: Double { willSet { print("すぐに値が設定されます", newValue) } didSet { print("以前の値は:", oldValue, ", 新しい値は:", celsius) } } init(celsius: Double) { self.celsius = celsius } } let temp = Temperature(celsius: 22) temp.celsius = 28 // willSetとdidSetが出力されます

主な特徴:

  • willSetオブザーバーでは、特別な変数newValueが利用可能です。
  • didSetでは、oldValueが利用可能です。
  • オブザーバーは、initでプロパティを初期化するときには呼び出されません。

トリック質問。

計算プロパティにオブザーバーを追加できますか?

いいえ、計算プロパティにはwillSetやdidSetを追加できません。なぜなら、計算プロパティにはすでに独自のgetterとsetterがあるからです。willSet/didSetはストレージプロパティのみに適用されます。

イニシャライザ内でプロパティが変更された場合、オブザーバーは呼び出されますか?

いいえ、プロパティオブザーバーは初期化中(init)には呼び出されません。それらはinitが完了した後に値が変更されたときにのみ発動します。

現在の値を自分自身に代入するとどうなりますか?たとえば、x = xのように?

オブザーバーは常に呼び出されます。たとえプロパティの値が変更されなかったとしても!これは副作用を引き起こす可能性があるため、注意が必要です。

var value: Int = 0 { didSet { print("didSetは常に呼び出されます!") } } value = value // didSetが呼び出されます

よくある間違いとアンチパターン

  • 副作用に依存:ビジネスロジックをdidSet/willSetにのみ実装すると、コードが不明瞭になります。
  • 値が変わっていない「空の」変更時に副作用を適切に管理しない。
  • 計算プロパティ用のオブザーバーを使用する代わりに、setterの中で動作を実装すること。

実生活の例

ネガティブケース

開発者はdidSetでUIを更新しましたが、値の変更を確認していませんでした。UIは「空の」代入時でも更新され、パフォーマンスが低下しました。

長所:

  • 実装が迅速で、コードが少ない。

短所:

  • 不要な操作が増え、デバッグが難しくなった。

ポジティブケース

didSetで古い値と新しい値の等価性を確認しました。インターフェースの更新は、実際に値が変更された場合にのみ行われました。

長所:

  • 副作用の最小化、高パフォーマンス。

短所:

  • 追加のifチェックが必要で、少しコードが増えます。