Home > Back-end >  How to convert value of optional type Binding<T?>? to Binding<T?> in SwiftUI?
How to convert value of optional type Binding<T?>? to Binding<T?> in SwiftUI?

Time:05-14

I have an init like so:

@Binding var height: Double?

init(height: Binding<Double?>? = nil) { 
 self._height = height
}

I am getting an error:

Value of optional type 'Binding<Double?>?' must be unwrapped to a value of type 'Binding<Double?>'

What would be the correct syntax so that I would not need to pass any value in init if it's not needed, but if I did pass the height it would then assign to the local binding variable?

Thanks.

CodePudding user response:

The process of "converting" an optional to a non-optional is unwrapping. The only way you can convert an optional to a non-optional is to provide some default value in the case where the optional is nil.

You have got a little confused about Swift optional vs default parameters.

Your problem here is you want your height argument to be optional (as in the caller doesn't need to specify it), but you shouldn't declare it as an optional because your object needs there to be an instance of a Binding - the binding must exist even though its wrapped value may be nil.

The type wrapped in the binding is an optional Double and that is what you need to provide as a default value - a binding to a Double?. You can do this with Binding.constant

struct SomeView {
    @Binding var height: Double? 
    init(height: Binding<Double?> = .constant(nil)) { 
        self._height = height
    }
}

Now your default value is a binding to a Double? and the wrapped value is nil

If you did want your caller to be able to explicitly pass nil for the height binding then you have to deal with the default value in the initialiser itself:

struct SomeView {
    @Binding var height: Double? 
    init(height: Binding<Double?>? = nil) { 
        self._height = height ?? .constant(nil)
    }
}

CodePudding user response:

There won't ever be a need to pass a binding to an optional. What you actually want is to be able to handle these two cases:

init(height: Binding<Double>) {
  _height = .init(height)
}

init() {
  _height = .constant(nil)
}

Which is closely emulated by using a default value:

init(height: Binding<Double>? = nil) {
  _height = height.map(Binding.init) ?? .constant(nil)
}
  • Related