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やdidSetを追加できません。なぜなら、計算プロパティにはすでに独自のgetterとsetterがあるからです。willSet/didSetはストレージプロパティのみに適用されます。
イニシャライザ内でプロパティが変更された場合、オブザーバーは呼び出されますか?
いいえ、プロパティオブザーバーは初期化中(init)には呼び出されません。それらはinitが完了した後に値が変更されたときにのみ発動します。
現在の値を自分自身に代入するとどうなりますか?たとえば、x = xのように?
オブザーバーは常に呼び出されます。たとえプロパティの値が変更されなかったとしても!これは副作用を引き起こす可能性があるため、注意が必要です。
var value: Int = 0 { didSet { print("didSetは常に呼び出されます!") } } value = value // didSetが呼び出されます
開発者はdidSetでUIを更新しましたが、値の変更を確認していませんでした。UIは「空の」代入時でも更新され、パフォーマンスが低下しました。
長所:
短所:
didSetで古い値と新しい値の等価性を確認しました。インターフェースの更新は、実際に値が変更された場合にのみ行われました。
長所:
短所: