Observable does not conform with Equatable (and Hashable)
I noticed a snag when using NavigationLink(value:label:)
and .navigationDestination(for:destination:)
with the new @Observable
vs the old Combine ObservableObject
(which “just worked™️”). There are 2 compilation errors:
Initializer 'init(value:label:)' requires that 'ObservableContent' conform to 'Hashable'
Instance method 'navigationDestination(for:destination:)' requires that 'ObservableContent' conform to 'Hashable'
Fortunately it is relatively simple to add Hashable
conformance to an @Observable
class by implementing a static func ==
and a func hash
that uses ObjectIdentifier as follows:
import SwiftUI
@Observable class ObservableContent: Hashable {
var text1 = "Default"
var text2 = ""
func hash(into hasher: inout Hasher) {
hasher.combine(ObjectIdentifier(self))
}
static func == (lhs: ObservableContent, rhs: ObservableContent) -> Bool {
lhs === rhs
}
}
struct ContentView: View {
@State var observableContent: ObservableContent?
var body: some View {
Group {
if let observableContent {
NavigationStack {
NavigationLink(value: observableContent) {
Text("Navigation Link")
}
.navigationDestination(for: ObservableContent.self) { content in
ObservableContentView(content: content)
}
}
}
}
.onAppear {
if observableContent == nil {
observableContent = ObservableContent()
}
}
.onDisappear {
observableContent = nil
}
}
}
struct ObservableContentView: View {
@Bindable var content: ObservableContent
var body: some View {
Form {
TextField("Text1", text: $content.text1)
Text(content.text1)
}
}
}
I also posted my solution to the Apple Developer solutions to help someone who faced the same problem: https://developer.apple.com/forums/thread/734848?answerId=786038022#786038022