3

I'm trying to use the new Swift Macros using @Observable and @Environment with the following code:

import SwiftUI
import Observation

@Observable class Note {
    var text = ""
}

struct ContentView: View {
    @State var note = Note()
    
    var body: some View {
        FormView()
            .environment(note)
    }
}

struct FormView: View {
    @Environment(Note.self) var note
    
    var body: some View {
        Form {
            TextField("write here", text: $note.text)
        }
    }
}

However, it's unable to build with the following error:

Cannot find '$note' in scope

Removing the $ in $note results in:

Cannot convert value of type 'String' to expected argument type 'Binding<String>'

malhal
  • 26,330
  • 7
  • 115
  • 133
ygee
  • 2,580
  • 3
  • 17
  • 21

1 Answers1

5

Currently (as of iOS 17/macOS 15 beta 2) objects received via an @Environment object aren’t directly bindable.

The workaround (as suggested by an Apple engineer in one of the WWDC slack rooms) is to redeclare a bindable local reference in your body:

struct FormView: View {
    @Environment(Note.self) var note
    
    var body: some View {
        @Bindable var note = note // add this line
        Form {
            TextField("write here", text: $note.text)
        }
    }
}

If you are frustrated with this, do file a feedback report with Apple – the more feedback we give them about elements like this, the higher priority a fix is likely to become.

malhal
  • 26,330
  • 7
  • 115
  • 133
ScottM
  • 7,108
  • 1
  • 25
  • 42
  • Thank you, this does work. But this kind of defeats the purpose of the macro for a cleaner code since it adds another line of code compared to the previous implementation. Apple should definitely fix this. – ygee Jun 24 '23 at 13:53