Using propertywrappers in function arguments

Hi,

Overview

  • I would like to know how to use property wrappers as function arguments
  • How do I get the following code to compile?
  • The error is seems confusing to me.

Compilation error

Cannot convert value 'number' of type 'Binding<Int>' to expected type 'Binding<Int>', use wrapper instead

Consider the following example:

import SwiftUI

@State var number = 10

func increment(@Binding number: Int) {
    number += 1
}

increment(number: $number) // Throws compilation error

Technically the spelling is:

-increment(number: $number)
+increment($number: $number)

However you won't get a completion signal from the compiler.

I'm not sure it's advisable to use this feature, though. I don't think any of Apple's frameworks leverage it, and when I've tried it in the past I hit compiler bugs very quickly.

4 Likes

Thank you so much @stephencelis, I was breaking my head over the syntax.

I have a few questions:

  • What do you mean by a won't get a completion signal from the compiler?
  • Just curious Is the bug on the Swift side or the framework (SwiftUI) side?

Thanks a lot for warning me not to use it. Hope it gets fixed so that it can be used in the future.

increment($number:) doesn't show up in autocomplete in your IDE or language server.

In the Swift compiler itself. I think because no major feature of the language or of its frameworks utilizes this feature, not a lot of the bugs have been found.

2 Likes

Thanks a lot @stephencelis for the clarification.

Fingers crossed it gets fixed.

I will continue using .wrappedValue for now

Perhaps you have a more elaborate example in mind. As for the quoted you could use either func increment(number: Binding<Int>) or a mere func increment(number: inout Int).

1 Like

Thanks @tera
The real use case is with a SwiftUI view passing its @State property as a Binding to the child view.

Yes Binding<Int> would work fine, but then I would have to use number.wrappedValue in a bunch of places.

I asked because I was hoping to have the convenience of @Binding so that things would look nicer (without using wrappedValue).

Since it is SwiftUI view inout wouldn't work well.

Something like this should work, then:

struct InnerView: View {
  @Binding var number: Int

  init(number: Binding<Int>) {
    self._number = number
  }

  var body: some View { ... }
}
3 Likes

Thanks @bbrk24 for the showing how to handle it in a view.