📝
StateStruct - structの読み書きを追跡するマクロライブラリを開発している話
はじめに
StateStructは、Swiftの構造体(struct)内での状態管理をサポートするライブラリです。Swiftマクロとコンパイラプラグインを活用して、プロパティの読み書きを追跡し、依存関係グラフを構築することで、状態の変更を検出します。
主要な機能
1. 依存関係の追跡
-
@Tracking
マクロを使用して、プロパティへのアクセスを追跡 - 読み取り操作:プロパティが読み取られた際に、そのアクセスパスが依存関係グラフに記録
- 書き込み操作:プロパティが変更された際に、変更グラフに記録
2. 変更検出
-
PropertyNode.hasChanges(writeGraph:readGraph:)
関数を使用して、読み取りと書き込みの依存関係グラフを比較 - 変更があったプロパティを検出し、必要な更新のみを実行
3. ネストされた状態のサポート
- フラットなプロパティだけでなく、深くネストされた構造体の状態変更も追跡可能にする
- そのネストされたtypeも@Trackingを持つ必要がある
- 例:
state.nested.name
のような階層構造のプロパティも追跡
4. Copy-on-Write (COW)の実装
- パフォーマンスを考慮し、Copy-on-Writeメカニズムを実装
- IntやArrayなど、COWにする必要のないものはknown-typesとして除外される
- 状態の変更が必要な場合のみコピーを作成
使用例
import StateStruct
@Tracking
struct MyState {
var height: Int = 0
var name: String = ""
var nested: Nested = .init(name: "")
@Tracking
struct Nested {
var name: String = ""
var age: Int = 18
}
}
// 状態の追跡を開始
var state = MyState()
state.startNewTracking()
// プロパティの読み取りを追跡
_ = state.height
_ = state.nested.name
let readTracking = state.trackingResult!
// プロパティの書き込みを追跡
state.startNewTracking()
state.height = 200
let writeTracking = state.trackingResult!
// 変更の検出
let hasChanged = PropertyNode.hasChanges(
writeGraph: writeTracking.graph,
readGraph: readTracking.graph
)
技術的な仕組み
-
マクロによるコード生成
- Swiftマクロを使用して、プロパティアクセスの追跡コードを挿入
- 追跡に必要なコードを自動生成
-
依存関係グラフの構築
- プロパティアクセス時に、PropertyPathオブジェクトを使用してアクセスパスを記録
- 読み取りと書き込みの依存関係を別々のグラフとして管理
ユースケース
利用している箇所
Discussion