0

So I'm currently getting to grips with swift and swiftui and have run into a problem with Observable objects. I want to be able to share the value of a variable over 2 different views so opted to use an Observable Object. The duration and interval variables will be set using a slider on the settings view, which will then be used for logic in my main view.


struct Settings: View {
    @EnvironmentObject var appInfo: AppInformation
    
    
    
    var body: some View {
        NavigationView {
            ZStack {
                VStack (spacing: 35){
                    HStack {
                        Text("Duration")
                            .font(.system(size: 23, weight: .bold, design: .rounded))
                            .padding(.leading, 25)
                        Spacer()
                        
                        Slider(value: appInfo.duration, in: 1...60, step: 1)
                            .padding(.trailing, 20)
                            .padding(.leading, 20)
                        Text("\(Int(appInfo.duration))")
                            .padding(.trailing, 30)
                            .font(.system(size: 23, weight: .medium, design: .rounded))
                    }
                    
                    .padding(.top, 100)
                    
                    
                    HStack {
                        Text("Interval  ")
                            .font(.system(size: 23, weight: .bold, design: .rounded))
                            .padding(.leading, 25)
                        Spacer()
                        
                        Slider(value: appInfo.interval, in: 1...60, step: 1)
                            .padding(.trailing, 20)
                            .padding(.leading, 20)
                        Text("\(Int(appInfo.interval))")
                            .padding(.trailing, 30)
                            .font(.system(size: 23, weight: .medium, design: .rounded)).navigationTitle("Settings")
                    }
                    Spacer()
                }
                
                
            }
            
        }
        
        
        
}
    

struct Settings_Previews: PreviewProvider {
    static var previews: some View {
        Settings()
            .environmentObject(AppInformation())
    }
}
    
}

class AppInformation: ObservableObject {
    var duration = 0.0
    var interval = 0.0
}

But when attempting to either preview or sun my app in the simulator, it throws an error 'A View.environmentObject(_:) for AppInformation may be missing as an ancestor of this view.'

It throws the error on these lines where I'm referencing the variable as a slider value, even though I have referenced the variable in a text view further down which didn't seem to have any problems.

                            .padding(.trailing, 20)
                            .padding(.leading, 20)
                        Text("\(Int(appInfo.duration))")
                            .padding(.trailing, 30)
                            .font(.system(size: 23, weight: .medium, design: .rounded))

Slider(value: appInfo.interval, in: 1...60, step: 1)
                            .padding(.trailing, 20)
                            .padding(.leading, 20)

1 Answers1

0

So first of all, your example code is not working.

Below you will find the fixed version. Both running in previews and in Simulator.

To answer your question:

If you use Settings anywhere in your Code, you have to pass it an environmentObject of AppInformation (See ContentView). Since you did not provide any source code in context I assume thats where your error is.

Here is a working example:

import SwiftUI
import CoreData

class AppInformation: ObservableObject {
    @Published var duration = 0.0
    @Published var interval = 0.0
}

struct Settings: View {
    @EnvironmentObject var appInfo: AppInformation

    var body: some View {
        NavigationView {
            ZStack {
                VStack (spacing: 35){
                    HStack {
                        Text("Duration")
                            .font(.system(size: 23, weight: .bold, design: .rounded))
                            .padding(.leading, 25)
                        Spacer()

                        Slider(value: $appInfo.duration, in: 1...60, step: 1)
                            .padding([.trailing, .leading], 20)
                        Text("\(Int(appInfo.duration))")
                            .padding(.trailing, 30)
                            .font(.system(size: 23, weight: .medium, design: .rounded))
                    }
                    .padding(.top, 100)

                    HStack {
                        Text("Interval  ")
                            .font(.system(size: 23, weight: .bold, design: .rounded))
                            .padding(.leading, 25)
                        Spacer()

                        Slider(value: $appInfo.interval, in: 1...60, step: 1)
                            .padding([.trailing, .leading], 20)
                        Text("\(Int(appInfo.interval))")
                            .padding(.trailing, 30)
                            .font(.system(size: 23, weight: .medium, design: .rounded))

                    }
                    Spacer()
                }
            }
            .navigationTitle("Settings")
        }
    }
}

struct Settings_Previews: PreviewProvider {
    static var previews: some View {
        Settings()
            .environmentObject(AppInformation())
    }
}

struct ContentView: View {
    @ObservedObject var appInformation = AppInformation()

    var body: some View {
        Settings()
            .environmentObject(appInformation)
    }

}

Also here are some tips using SwiftUI:

  • If you need to set padding on multiple edges you can use also use .padding([.trailing, .leading], 20)
  • You should set the .navigationTitle("Settings") modifier on the outer child of the view - but within the NavigationView
  • You can also set the .font modifier on the VStack or HStack, this would apply it to all children (including the Slider Label)
Ali
  • 761
  • 1
  • 5
  • 24