How Is Optional Binding Used in Swift

How is optional binding used in swift?

First someOptional is checked to see if it's nil or has data. If it's nil, the if-statement just doesn't get executed. If there's data, the data gets unwrapped and assigned to constantName for the scope of the if-statement. Then the code inside the braces is executed.

if let constantName = someOptional {
statements
}

There's no way to chain this functionality in one if-statement. let constantName = someOptional does not directly evaluate to a boolean. It's best to think of "if let" as a special keyword.

Why use optional binding?

You use optional binding (if let) if you have a block of code that you only want to run if the variable is not nil.

You use optional chaining (the ?) only when accessing the properties/methods of an optional variable.

But there are situations where optional chaining is not possible (i.e. you're not accessing a property/method of the optional variable, but rather using that variable for other purposes). For example

// let's assume `data` is a `NSData?` optional

if let imageData = data {
let image = UIImage(data: imageData)

// now do something with `image`
}

We do this because in this context, we can't use optional chaining, and using forced unwrapping (e.g. let image = UIImage(data: data!)) would crash if data was nil.

what's the meaning of optional binding in swift

Advantages of the Optional binding over If Statements and Forced Unwrapping:

  • local variable which is not an optional and a shortcut when a structure is deeper than one level

Context:

You have three techniques to work with an optionals:

  • Optional binding
  • If statements and forced unwrapping
  • Optional chaining

Optional binding

You use optional binding to find out whether an optional contains a
value, and if so, to make that value available as a temporary constant
or variable. Optional binding can be used with if and while statements
to check for a value inside an optional, and to extract that value
into a constant or variable, as part of a single action.

If Statements and Forced Unwrapping

You can use an if statement to find out whether an optional contains a
value by comparing the optional against nil. You perform this
comparison with the “equal to” operator (==) or the “not equal to”
operator (!=).

Optional chaining

Optional chaining is a process for querying and calling properties,
methods, and subscripts on an optional that might currently be nil. If
the optional contains a value, the property, method, or subscript call
succeeds; if the optional is nil, the property, method, or subscript
call returns nil. Multiple queries can be chained together, and the
entire chain fails gracefully if any link in the chain is nil.

source


struct Computer {
let keyboard: Keyboard?
}

struct Keyboard {
let battery: Battery?
}

struct Battery {
let price: Int?
}

let appleComputer: Computer? = Computer(keyboard: Keyboard(battery: Battery(price: 10)))

func getBatteryPriceWithOptionalBinding() -> Int {
if let computer = appleComputer {
if let keyboard = computer.keyboard {
if let battery = keyboard.battery {
if let batteryPrice = battery.price {
print(batteryPrice)
return batteryPrice
}
}
}
}
return 0
}

func getBatteryPriceWithIfStatementsAndForcedUnwrapping() -> Int {
if appleComputer != nil {
if appleComputer!.keyboard != nil {
if appleComputer!.keyboard!.battery != nil {
if appleComputer!.keyboard!.battery!.price != nil {
print(appleComputer!.keyboard!.battery!.price!)
return appleComputer!.keyboard!.battery!.price!
}
}
}
}
return 0
}

func getBatteryPriceWithOptionalChainingAndForcedUnwrapping() -> Int {
if appleComputer?.keyboard?.battery?.price != nil {
print(appleComputer!.keyboard!.battery!.price!)
return appleComputer!.keyboard!.battery!.price!
}
return 0
}

func getBatteryPriceWithOptionalChainingAndOptionalBinding() -> Int {
if let price = appleComputer?.keyboard?.battery?.price {
print(price)
return price
}
return 0
}

func getBatteryPriceWithOptionalChainingAndNilCoalescing() -> Int {
print(appleComputer?.keyboard?.battery?.price ?? 0)
return appleComputer?.keyboard?.battery?.price ?? 0
}

Bridging Optional Binding to Non-Optional Child (SwiftUI)

Child should take a Binding to the non-optional string, rather than using @State, because you want it to share state with its parent:

struct Child: View {
// within Child, I'd like the value to be NonOptional
@Binding var text: String

var body: some View {
TextField("OK: ", text: $text).multilineTextAlignment(.center)
}
}

Binding has an initializer that converts a Binding<V?> to Binding<V>?, which you can use like this:

            if let binding = Binding<String>($model.name) {
Child(text: binding)
}

If you're getting crashes from that, it's a bug in SwiftUI, but you can work around it like this:

            if let text = model.name {
Child(text: Binding(
get: { model.name ?? text },
set: { model.name = $0 }
))
}

Converting optional Binding to non-optional Binding

Binding has an associated type Value already, so by trying to use T, you're putting a new generic on top of Value, which already exists.

But, you will still end up using T because you'll want to constrain Value to scenarios where it is Optional:

extension Binding {
func safeBinding<T>(defaultValue: T) -> Binding<T> where Value == Optional<T> {
.init {
self.wrappedValue ?? defaultValue
} set: { newValue in
self.wrappedValue = newValue
}
}
}

As noted in the comments, the Xcode compiler has difficulty if just Binding.init is used (note that I used just .init). This can be solved by explicitly using Binding<T>.init:

extension Binding {
func safeBinding<T>(defaultValue: T) -> Binding<T> where Value == Optional<T> {
Binding<T>.init {
self.wrappedValue ?? defaultValue
} set: { newValue in
self.wrappedValue = newValue
}
}
}

OR condition for optional binding?

Unfortunately I don't think this is possible in a single line (like if let x = y || let z = a {}). Logically it wouldn't make sense, because you would end up in a state where both variables would remain optional (if either is unwrapped, you don't know which is unwrapped or if both are). I think you'll need to take some other approach to this problem. I think the simplest form would be something like

if let unwrappedProperty1 = property1 {
handleProperty(unwrappedProperty1)
} else if let unwrappedProperty2 = property2 {
handleProperty(unwrappedProperty2)
}

or you could do something like

if let unwrappedProperty = property1 ?? property2 {
handleProperty(unwrappedProperty)
}

which would give priority to property1

How to assign an optional Binding parameter in SwiftUI?

@Binding var searchTxt: String?

init(searchTxt: Binding<String?>?) {
self._searchTxt = searchTxt ?? Binding.constant(nil)
}

Update: I prefer this one. TextField("", text: $text ?? "default value")

https://stackoverflow.com/a/61002589/4728060

func ??<T>(lhs: Binding<Optional<T>>, rhs: T) -> Binding<T> {
Binding(
get: { lhs.wrappedValue ?? rhs },
set: { lhs.wrappedValue = $0 }
)
}

Optional State or Binding in SwiftUI

Here is working example of optional with State and Binding:



import SwiftUI

struct ContentView: View {

@State private var progress: Int?

var body: some View {

CustomView(progress: $progress)

}
}


struct CustomView: View {

@Binding var progress: Int?

var body: some View {

Button("update") {

if let unwrappedInt = progress { progress = unwrappedInt + 1 }
else { progress = 0 } //<< █ █ Here: initializing! █ █

}
.onChange(of: progress) { newValue in

if let unwrappedInt = progress { print(unwrappedInt) }

}

}
}

Optional Binding, what exactly the word Binding means here?

Does the Binding mean the action of assigning the valid value into the temporary constant/variable? I.e. "binding" those two things together?

Yes. Basically, assignment of a value to a variable name is a binding — it "binds" the name to the value. So even this is a binding:

let x = 1

What's special with if let is that the binding takes place only if the value is an Optional that can be safely unwrapped (that is, it is not nil). If it can't be unwrapped safely, it is not unwrapped and no binding takes place (and the if condition fails).



Related Topics



Leave a reply



Submit