34

I'm building an app using SwiftUI and would like a way to convert a Binding<Value?> to a Binding<Value>.

In my app I have an AvatarView which knows how to render an image for a particular user.

struct AvatarView: View {
  @Binding var userData: UserData

  ...
}

My app holds a ContentView that owns two bindings: a dictionary of users by id, and the id of the user whose avatar we should be showing.

struct ContentView: View {
  @State var userById: Dictionary<Int, UserData>
  @State var activeUserId: Int

  var body: some View {
    AvatarView(userData: $userById[activeUserId])
  }
}

Problem: the above code doesn't combine because $userById[activeUserId] is of type Binding<UserData?> and AvatarView takes in a Binding<UserData>.

Things I tried...

  • $userById[activeUserId]! doesn't work because it's trying to unwrap a Binding<UserData?>. You can only unwrap an Optional, not a Binding<Optional>.

  • $(userById[activeUserId]!) doesn't work for reasons that I don't yet understand, but I think something about $ is resolved at compile time so you can't seem to prefix arbitrary expressions with $.

rjkaplan
  • 3,138
  • 5
  • 27
  • 33
  • Did you try `$userById[activeUserId] as! Binding`? – Kamran Oct 09 '19 at 04:59
  • Thanks for the suggestion! I think it would probably work fine, but I would prefer not to do an unsafe cast. When I try it I get a build warning saying "Cast from Binding to unrelated type Binding" – rjkaplan Oct 09 '19 at 05:18

1 Answers1

55

You can use this initialiser, which seems to handle this exact case - converting Binding<T?> to Binding<T>?:

var body: some View {
    AvatarView(userData: Binding($userById[activeUserId])!)
}

I have used ! to force unwrap, just like in your attempts, but you could unwrap the nil however you want. The expression Binding($userById[activeUserId]) is of type Binding<UserData>?.

Sweeper
  • 213,210
  • 22
  • 193
  • 313
  • WARNING! This will crash if the binding is later set to nil, as described here: https://stackoverflow.com/questions/63958106/exception-when-setting-an-optional-binding-to-nil-in-swiftui-after-checking – Rick Nov 06 '22 at 19:47
  • @Rick that's the same with any force unwrap. You just need to handle the nil case eg using an if let – Jonathan. Aug 31 '23 at 09:30