Skip to content

FB23801704: Landmark struct's mismatched Equatable/Hashable implementation in sample code prevents SwiftUI updates #825

Description

@malhal

Submission Date

2026-07-16

Status

Open

Area

Developer Documentation

Operating System Version

iOS 26

Type

Incorrect/Unexpected Behavior

Description

https://developer.apple.com/documentation/swiftui/landmarks-building-an-app-with-liquid-glass

In the provided sample project, the Landmark struct (which conforms to Hashable, Identifiable, and Transferable) implements custom Equatable and Hashable behavior by comparing and hashing only its id property:

static func == (lhs: Landmark, rhs: Landmark) -> Bool {
    return lhs.id == rhs.id
}

func hash(into hasher: inout Hasher) {
    hasher.combine(id)
}

While equating identity (id) with equality (==) is a common mistake, doing so in an official Apple developer sample promotes a severe anti-pattern that directly breaks SwiftUI's rendering pipeline.

Why this is a bug:
SwiftUI relies on Equatable (==) to determine whether a view's input data has changed and if the view needs to be redrawn. Because this custom implementation asserts that two Landmark instances are equal if their IDs match, any changes to other properties (such as updating a name, a description, a photo, or a favorite status) will be ignored by SwiftUI. If a parent view passes a mutated Landmark to a child view, the child view will fail to re-evaluate or redraw because oldLandmark == newLandmark incorrectly evaluates to true.

Steps to Reproduce

  1. Download and run the sample project.
  2. Observe the custom == and hash(into:) overrides on the Landmark model struct.
  3. Pass a Landmark instance into a subview.
  4. Mutate any property of that landmark instance other than the id (e.g., toggle a boolean or change a text string).
  5. Notice that the subview observing the instance fails to update its UI because SwiftUI's diffing engine assumes no change occurred.

Expected Behavior
The Landmark model should use memberwise equality (comparing all properties that contribute to the visual representation of the landmark) so that SwiftUI can accurately detect property mutations and trigger UI redraws.

Suggested Fix
The safest and cleanest approach is to remove the manual == and hash(into:) implementations entirely.
Since all properties of Landmark conform to Hashable, removing these manual overrides allows the Swift compiler to synthesize the correct, highly optimized memberwise conformity automatically:

// Correct, simplified struct definition
struct Landmark: Hashable, Identifiable, Transferable {
    var id: Int
    var name: String
    var park: String
    var state: String
    var description: String
    // ... other properties
    
    // (Manual == and hash(into:) implementations removed)
}

Letting the compiler handle this ensures that identity (Identifiable.id) is properly decoupled from value state equality (Equatable), resolving the rendering bugs.

Keywords

Sample Code

Prerequisites

  • The title follows the format FB<number>: <title>
  • I will keep this issue updated with Apple's responses

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions