3

After upgrading to Xcode 11 Beta 4, I starting seeing an error when using String(format: , args) with @State property. See code below. Second Text line throws an error:

Expression type 'String' is ambiguous without more context

while Texts 1, 3, and 4 work just fine.

struct ContentView : View {
    @State var selection = 2

    var body: some View {
        VStack {
            Text("My selection \(selection)") // works
            Text("My selection \(String(format: "%02d", selection))") // error
            Text("My selection \(String(format: "%02d", Int(selection)))") // works
            Text("My selection \(String(format: "%02d", $selection.binding.value))") // works
        }
    }
}

I realize this is Beta software, but was curious if anyone can see a reason for this behavior or is this simply a bug. If this can't be explained, I'll file a radar.

Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
Kon
  • 4,023
  • 4
  • 24
  • 38

2 Answers2

8

In beta 4, the property wrapper implementation changed slightly. In beta 3, your View was rewritten by the compiler as:

internal struct ContentView : View {
  @State internal var selection: Int { get nonmutating set }
  internal var $selection: Binding<Int> { get }
  @_hasInitialValue private var $$selection: State<Int>
  internal var body: some View { get }
  internal init(selection: Int = 2)
  internal init()
  internal typealias Body = some View
}

while on Beta 4, it does this:

internal struct ContentView : View {
  @State @_projectedValueProperty($selection) internal var selection: Int { get nonmutating set }
  internal var $selection: Binding<Int> { get }
  @_hasInitialValue private var _selection: State<Int>
  internal var body: some View { get }
  internal init(selection: Int = 2)
  internal init()
  internal typealias Body = some View
}

Now I am guessing: this change makes it more difficult for the compiler to infer the type of your variable? Note that another alternative that does work, is helping the compiler a little, by casting selection as Int:

Text("My selection \(String(format: "%02d", selection as Int))")
kontiki
  • 37,663
  • 13
  • 111
  • 125
0

Update (Xcode 11.2)

I also get the error:

'inout Path' is not convertible to '@lvalue Path'

with this code:

struct ContentView : View {
    @State var selection = 2

    var body: some View {
        VStack {
            Text(String(format: "%d", selection)) // does not work
        }
    }
}

Solved by and adding the $ prefix and then accessing wrappedValue in String(format:, args:):

struct ContentView : View {
    @State var selection = 2

    var body: some View {
        VStack {
            Text(String(format: "%d", $selection.wrappedValue)) // works
        }
    }
}
elight
  • 562
  • 2
  • 17