Passing around references to SwiftUI Bindings in places that are not Views

New to the forum and I hope this is an appropriate question.

To understand SwiftUI better under the hood, I am experimenting with passing around Bindings outside of Views. This is probably a bad idea. But I am hoping it throws some light on the lives of Binding variables and what happens to them in memory.

So today I tried to use a Binding as an associated value in an enum. The compiler tells me the resulting enum fails to conform to the Hashable and Equatable protocols. I believe it is because it is impossible for Binding to ever satisfy the needs of Hashable. But I'm not certain.


enum AppRoute: Equatable, Hashable {
     case welcomeScreen
     case slideshow(index: Binding<Int>) 

     static func ==(lhs: AppRoute, rhs: AppRoute) -> Bool {
         // Some Equatable-conforming logic here to get at wrapped values
         return lhs.hashValue == rhs.hashValue

         // It seems like the tricky bit is that Binding cannot ever conform to Hashable. Or could it, with the right extension?
     }
}

So is it impossible to pass SwiftUI bindings around, outside of relationships between Views? I am also wondering (hypothetically) if it might be possible using lower-level references like unsafe pointers.
I realize this is not the standard use case for @State and @Binding. Most likely this way lies madness. But basically I'm just curious about the survival of SwiftUI bindings outside of Views. And whether it is ever worth manipulating them from non-View classes.

Sure, pass them around. No problems. Embed them in enums with associated values, also no problem.
But you cannot, as you've found out, use them where some hashable value is expected.

1 Like

I am not entirely sure if this is good approach to conform Binding to Equatable and Hashable but this might work for you

extension Binding: Equatable where Value: Equatable {
    public static func == (lhs: Binding<Value>, rhs: Binding<Value>) -> Bool {
        lhs.wrappedValue == rhs.wrappedValue
    }
}
extension Binding: Hashable where Value: Hashable {
    public func hash(into hasher: inout Hasher) {
        hasher.combine(self.wrappedValue)
    }
}

enum AppRoute: Equatable, Hashable {
    case welcomeScreen
    case slideshow(index: Binding<Int>)
}