SwiftUI无需模型遵循Equatable协议?其重绘机制与效率探讨
Great question—this cuts to the core of how SwiftUI handles view identity and updates, which is a super common point of confusion for developers getting to grips with the framework. Let’s break this down step by step:
1. Identifiable is about view identity, not content equality
First, let’s clarify what Identifiable does. Its sole job is to give SwiftUI a stable way to track which view corresponds to which model in a collection (like a list or grid). When your models conform to Identifiable, SwiftUI uses the id property to match old and new views during its diffing process:
- If an
idexists in the new collection but not the old, SwiftUI adds a new view. - If an
idexists in the old but not the new, SwiftUI removes that view. - If an
idis present in both, SwiftUI knows it’s the same view and can update it in place (instead of tearing it down and rebuilding it).
Without Identifiable, SwiftUI falls back to comparing elements by their position in the collection—this leads to buggy behavior (like wrong animations when reordering items) and unnecessary view rebuilds.
2. SwiftUI doesn’t need Equatable because it uses other update triggers
So why not require Equatable to check if the model’s content changed? Because SwiftUI has built-in mechanisms to detect when updates are needed, regardless of Equatable:
- For ObservableObject models: When you use
@ObservedObjector@StateObject, SwiftUI listens to the model’s@Publishedproperties. If any of those properties change, the model sends a notification, and SwiftUI updates only the views that depend on that changed property. Theidtells SwiftUI which view to update, and the@Publishedchanges tell it what to update. - For value-type models (structs): If your Identifiable model is a struct stored in
@Stateor passed via@Binding, SwiftUI automatically compares the old and new values (even withoutEquatableconformance). If the values are different, it updates the view. If you do conform toEquatable, you can customize this comparison (e.g., ignore properties that don’t affect the UI) to make the check more efficient.
3. What happens when the same id has different content?
Let’s split this into two cases:
- ObservableObject: If the
idis the same but the model’s content changes (via a@Publishedproperty), SwiftUI gets a notification from the model and updates the corresponding view. It doesn’t need to check for equality because the publisher already told it something changed. - Value-type struct: SwiftUI will compare the old and new struct instances. If they’re different (even with the same
id), it updates the view. If they’re the same, it skips the update.
4. Is this approach inefficient?
Short answer: No—SwiftUI is designed to be extremely efficient even without Equatable. Here’s why:
- View updates are granular: SwiftUI only updates the parts of the view hierarchy that depend on the changed state, not the entire screen.
- Views are lightweight structs: "Redrawing" a SwiftUI view doesn’t mean rebuilding the underlying UIKit/AppKit view—it just means recalculating the view’s description, which is fast.
- The diffing algorithm is optimized: SwiftUI’s diffing logic (powered by
Identifiable) ensures that only necessary views are added, removed, or updated.
That said, adding Equatable conformance to value-type models can give you an extra layer of optimization, especially if your model has properties that don’t affect the UI. By customizing the == operator to ignore those properties, you can prevent unnecessary updates.
Wrapping up
To recap:
Identifiablesolves the problem of tracking view identity in collections.Equatablesolves the problem of checking if content has changed (for optimization).- SwiftUI doesn’t mandate
Equatablebecause it has other, more direct ways to detect updates (publishers for reference types, value comparison for structs). - Even without
Equatable, SwiftUI’s update mechanism remains efficient thanks to its granular diffing and lightweight view design.
内容的提问来源于stack exchange,提问作者Cheok Yan Cheng

