Search code examples
swiftxcodeswiftuiswift5swift-macro

How to use Swift Macros with @Observable and @Environment?


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>'


Solution

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