Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SwiftUI EnvironmentObject not available in View initializer?

Tags:

swiftui

I passed the environmentObject appSettings into my view successfully. I can use it to modify my font and the picker in my View. But if I try to access an environmentObject published variable in the view init() it crashes with:

Thread 1: Fatal error: No ObservableObject of type AppSettings found.
A View.environmentObject(_:) for AppSettings may be missing as an ancestor of this view.

Are there special rules about using an environmentObject in a custom SwiftUI View initializer?

Here's the start of my view code. The environmentObject is appSettings. If I comment out line 2 in my initializer and uncomment line 3 the app works. Note that I use "appSettings.interfaces" successfully later in my Picker.

struct CaptureFilterView: View {

@State var etherCapture: EtherCapture? = nil
@EnvironmentObject var appSettings: AppSettings
@Binding var frames: [Frame]
@State var captureFilter: String = ""
@State var error: String = ""
@State var numberPackets = 10

@State var interface: String = ""
init(frames: Binding<[Frame]>) {
    self._frames = frames
    self.interface = appSettings.interfaces.first ?? "en0" //CRASH HERE
    //self.interface = "en0"  //uncomment this and comment line above to make app "work"
}
var body: some View {
    HStack() {
        ...
        Picker(selection: $interface, label: Text("")) {
            ForEach(appSettings.interfaces, id: \.self) { interfaceName in
                Text(interfaceName).tag(interfaceName)
            }
        }

Here's where I create my top-level content view in my AppDelegate.swift

        let contentView = ContentView(showCapture: true).environmentObject(appSettings)

And just to be sure I also pass on the environmentObject when creating my CaptureFilterView in my top level ContentView. This is not necessary and does not change the behavior.

            if showCapture { CaptureFilterView(frames: self.$frames).environmentObject(appSettings) }

For reference here is the top of my appSettings:

class AppSettings: ObservableObject {
    @Published var font: Font
    @Published var interfaces: [String]
like image 960
Darrell Root Avatar asked Mar 03 '23 18:03

Darrell Root


1 Answers

SwiftUI EnvironmentObject not available in View initializer?

Yes, SwiftUI EnvironmentObject not available in View initializer. Why? It is simple - it is injected after object initialiazation.

Let's consider how it is done on example of above ContentView:

let contentView = ContentView(showCapture: true).environmentObject(appSettings)

so what's going on here? Here

  1. instantiation & initialisation of value for the type ContentView
let newInstance = ContentView.init(showCapture: true) 
  1. calling function func environmentObject() on newInstance injected appSetting property
let contentView = newInstance.environmentObject(appSettings)
like image 124
Asperi Avatar answered Mar 21 '23 15:03

Asperi