Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I unwrap an optional value inside a binding in Swift?

Tags:

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 $.

like image 691
rjkaplan Avatar asked Oct 09 '19 04:10

rjkaplan


People also ask

How does Swift handle optional value?

An optional String cannot be used in place of an actual String . To use the wrapped value inside an optional, you have to unwrap it. The simplest way to unwrap an optional is to add a ! after the optional name. This is called "force unwrapping".

How do I force unwrap in Swift?

Even though Swift isn't sure the conversion will work, you can see the code is safe so you can force unwrap the result by writing ! after Int(str) , like this: let num = Int(str)! Swift will immediately unwrap the optional and make num a regular Int rather than an Int? .

What is optional binding Swift?

Optional Binding is used to safely unwrap the optional value. Step one: We assign our optional value to temporary constant & variable. Step Two: If the optional variable contains a value it will be assigned to our temporary variable.


Video Answer


1 Answers

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>?.

like image 83
Sweeper Avatar answered Oct 14 '22 13:10

Sweeper