willSetとdidSetは、Swiftのプロパティオブザーバー(property observers)であり、プロパティの値が変更される前後にコードを実行できます。computed propertiesとは異なり、オブザーバーは新しい値を計算せず、変更に反応するだけです。Appleのドキュメント『The Swift Programming Language』(2026年)によると、オブザーバーはデータ検証、インターフェースの同期、コード内の変更のログ記録に不可欠です。
重要なポイント
willSetとdidSetは、Swiftのプロパティオブザーバー(property observers)であり、stored propertiesの変更を追跡する組み込みのメカニズムです。
手動でのsetter実装やコールバックシステムが必要な他の言語とは異なり、Swiftは変更に反応するための宣言的な構文を提供します。オブザーバーはプロパティ宣言の直後に追加され、別途呼び出す必要はありません。
Apple Developer Documentation(2026年)によると、property observersは任意のクラス、構造体、または列挙型のstored propertiesでサポートされています。computed propertiesでは機能しません。値が格納されないためです。computed propertiesの場合、変更への反応はsetter内で直接実装されます。
willSetは、プロパティに新しい値が割り当てられる直前に呼び出されます。willSet内では、暗黙的なパラメーターnewValueが利用可能で、設定される値を含みます。この時点では、プロパティの現在の値はまだ変更されていません。プロパティを介して直接古い値を読み取ることができます。
Swift Evolution提案SE-0001(2024年)によると、willSetは実際の変更前に検証またはログ記録を行う機能を提供します。willSetで例外がスローされた場合、新しい値は適用されず、オブザーバーはデータ保護メカニズムとして機能します。
didSetは、新しい値が割り当てられた直後に呼び出されます。didSet内では、暗黙的なパラメーターoldValueが利用可能で、変更前の値を含みます。この時点で、プロパティにはすでに新しい値が含まれており、古い値と比較できます。
Swift by Sundell(2025年)によると、didSetは最も人気のあるオブザーバーです。これは、UIの更新、依存フィールドの再計算、変更後のサーバーへのデータ送信などの後処理で最も頻繁に必要とされるためです。
Property observersは、プロパティの直後に波括弧を使用して宣言されます。最小限の構文では1つのオブザーバーのみ必要ですが、両方を宣言することもできます。
var score: Int = 0 {
willSet {
print("スコアが\(newValue)に変わります")
}
didSet {
print("スコアが\(oldValue)から\(score)に変わりました")
}
}
両方のオブザーバーはオプションです。willSetのみ、didSetのみ、または両方を指定できます。willSetでは、括弧内に名前を指定してnewValueの名前を変更できます。
var username: String = "guest" {
willSet(newName) {
print("\(newName)を設定しようとしています")
}
didSet(oldName) {
print("以前は\(oldName)、現在は\(username)")
}
}
Swift Language Guide(2026年)によると、パラメーターの名前を変更すると、特に長い名前を持つ大規模プロジェクトでプロパティとオブザーバーを使用する場合に、コードの可読性が向上します。
実行順序は厳密に定義されています。最初にwillSet(古い値が利用可能)、次に代入、次にdidSet(新しい値が利用可能)です。
class Temperature {
var celsius: Double = 0.0 {
willSet {
print("気温が\(celsius)から\(newValue)に変わります")
}
didSet {
if celsius > 100.0 {
print("沸点を超えました!")
}
}
}
}
重要な制限事項:インスタンス作成時のプロパティ初期化中はオブザーバーは呼び出されません。init内での値の代入はwillSetとdidSetをトリガーしません。これにより、構築段階での望ましくない副作用が防止されます。
Apple Swift Blog(2025年)によると、この動作は、コンストラクターでもsetterが呼び出される多くの他の言語とは異なります。Swiftは安全性を選択しており、オブザーバーはオブジェクトの初期化が完了した後にのみ動作を開始します。
didSet内でプロパティを変更すると、オブザーバーが繰り返し呼び出される可能性があります。Swiftは再帰をブロックしません。プログラマーが手動で制御する必要があります。
var counter: Int = 0 {
didSet {
if counter < 5 {
counter += 1
}
}
}
このようなコードは、終了条件が提供されない場合、スタックオーバーフローを伴う完全な再帰を引き起こします。Stack Overflow Swift Community(2025年)によると、これはproperty observersを扱う際に初心者が犯す最も一般的な間違いの1つです。
構造体は、stored propertiesに対してwillSetとdidSetを制限なくサポートしています。構造体は値型であり、mutatingメソッド内でのプロパティの変更もオブザーバーをトリガーすることを覚えておくことが重要です。
struct Point {
var x: Double = 0.0 {
didSet {
print("Xが\(x)に変わりました")
}
}
var y: Double = 0.0 {
didSet {
print("Yが\(y)に変わりました")
}
}
}
var point = Point()
point.x = 5.0
プロパティオブザーバーは、SwiftプロジェクトでUI同期からデータ検証やログ記録まで、幅広いタスクに使用されています。
didSetを使用すると、無効な値が設定された直後にロールバックまたは修正できます。これにより、Objective-Cの煩雑なsetterが不要になり、モデルレベルでのデータ整合性が確保されます。
var age: Int = 0 {
didSet {
if age < 0 || age > 150 {
age = oldValue
}
}
}
関連するプロパティが変更されると、別途更新メソッドを呼び出すことなく、インターフェース要素を自動的に更新できます。
var userName: String = "" {
didSet {
nameLabel.text = userName
}
}
willSetは、デバッグや監査を目的としたログ記録に便利です。適用する前に時刻と新しい値を記録できるため、ログに分析用の元データが含まれていることが保証されます。
objc.io(2025年)によると、property observersは、単方向データフローを採用するアーキテクチャで特に有用であり、すべてのプロパティ変更が記録され、後で状態を再現できます。
Computed propertiesはその場で値を計算し、ストレージを持ちません。一方、willSetとdidSetは実際の値を持つstored propertyで動作します。
| 特性 | Property Observers | Computed Properties |
|---|---|---|
| 値の保存 | あり | なし |
| 変更時にコードを実行 | あり | なし |
| 宣言タイプ | var | var (get/set) |
| アクセスパラメーター | newValue、oldValue | newValue(set内) |
| 初期化 | 初期値が必要 | 不要 |
主な違い:computed propertyはアクセスごとに値を計算しますが、property observerは既存の値の変更に反応します。どちらを選ぶかは意味論に基づきます。プロパティが他のデータから派生する場合はcomputedを、変更を監視する必要がある独立した値の場合はwillSet/didSetを使用します。
最も一般的な間違いは、終了条件なしでのdidSetの再帰呼び出しです。didSet内でのプロパティ変更ごとにオブザーバーが再度トリガーされ、無限ループに陥ります。
2番目に一般的な間違いは、letプロパティにオブザーバーを使用しようとすることです。letは定数であるため、Swiftコンパイラーがエラーを出力します。
3番目の間違いは、初期化中にオブザーバーが呼び出されないことを無視することです。init内でwillSetが起動することを期待する開発者は、予期しない動作に遭遇します。
4番目の問題は、拡張機能内のプロパティにオブザーバーを適用することです。Swiftは、拡張機能内のstored propertiesにwillSet/didSetを追加することを禁止しています。
Ray Wenderlich(2025年)によると、これらの制限を理解することで、早期にバグを回避でき、Swiftコードの予測可能性が向上します。
よくある質問
はい。各オブザーバーはオプションです。willSetのみ、didSetのみ、または両方を同時に宣言できます。
いいえ。Swiftは、拡張機能内のstored propertiesにwillSetとdidSetを追加することを禁止しています。オブザーバーは元の型定義でのみ宣言されます。
いいえ。初期化中はオブザーバーは呼び出されません。これは、オブジェクト構築段階での副作用を防ぐ保護メカニズムです。
willSetは、値が変更される前に実行されるstored propertyオブザーバーです。computed propertyのsetterは新しい値を計算する方法であり、既存の値を監視するものではありません。
繰り返しdidSetを呼び出すと再帰が発生します。終了条件がない場合、スタックオーバーフローが発生してプログラムが終了します。
まとめ
ターンキー方式のモバイルアプリケーションを開発します
IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。