How to optionally pass in a Binding in SwiftUI?

The main problem with what you want to achieve is that when the index is handled by the parent your View needs a @Binding to it, but when it handles the index itself it needs @State. There are two possible solutions.

If the view can ignore the index property when it doesn't have one:

struct ReusableView: View {

    @Binding var index: Int?

    init(_ index: Binding<Int?>) {
        self._index = index
    }

    init() {
       self._index = .constant(nil)
    }

    var body: some View {
        VStack {
            index.map { Text("The index is \($0)") }
        }
    }   
}

The advantage is that it is very straightforward - just two initializers, but you cannot change the value of the index when it is handled by ResusableView itself (its a constant).

If the view cannot ignore the index property when it doesn't have one:

struct ReusableView: View {

    private var content: AnyView

    init(_ index: Binding<Int>? = nil) {
        if let index = index {
            self.content = AnyView(DependentView(index: index))
        } else {
            self.content = AnyView(IndependentView())
        }
    }

    var body: some View {
        content
    }

    private struct DependentView: View {

        @Binding var index: Int

        var body: some View {
            Text("The index is \(index)")
        }
    }

    private struct IndependentView: View {

        @State private var index: Int = 0

        var body: some View {
            Text("The index is \(index)")
        }
    }

}

The clear advantage is that you have a view that can either be bound to a value or manage it as its own State. As you can see ReusableView is just a wrapper around two different views one managing its own @State and one being bound to @State of its parent view.

Tags:

Swift

Swiftui