0

can someone please help me with this. Whenever I am trying to declare gp as an Environment object, the list disappears. The list works fine when the gp is a @State variable. Could you please help me with creating gp as a global variable so that it works in another screen of Final. I want to call gp in the Final screen so that I can use the value of gp to calculate something else.

import SwiftUI
    
    
    struct Calculation: View {
        
        @State var load1 = Float()
        @State var load2 = Float()
        //@State var gp : Float = 0
        @State var rate: Float = 0
        @ObservedObject var taskStore = TaskStore()
        @EnvironmentObject var userSettings: UserSettings
        func addNewToDo() {
            taskStore.tasks.append(Task(id: String(taskStore.tasks.count + 1), toDoItem: " Earning: =  \(rate.description)", amount: rate))
        }
        
        var body: some View {
            NavigationView {
                VStack {
                    List {
                        
                        Section(header:Text("load 2"))
                        {
                            TextField("Enter value of load 1", value: $load1, format: .number)
                            TextField("Enter value of load 1", value: $load2, format: .number)
                        }
                        
                        HStack {
                            Button(String(format: "Add Load"), action: {
                                print("pay for the shift is ")
                                print(Rocky(mypay: rate))
                                userSettings.gp += rate
                            })
                            
                            Button(action: {
                                addNewToDo()
                                Rocky(mypay: rate)
                            },
                            label: {
                                Text(" ")
                            })
                        }
                        
                        ForEach(self.taskStore.tasks) { task in
                            Text(task.toDoItem)
                        }
                        .onMove(perform : self.move)
                        .onDelete(perform : self.delete) //For each
                        
                    }
                    .navigationBarTitle("SHIFTS")
                    .navigationBarItems(trailing: EditButton()) //List
                    
                    Text("Gross Pay = $\(userSettings.gp) ")
                     NavigationLink(destination: Final(), label: {Text("Next")})
                }.onAppear()
                
            }
        }
        
        func Rocky(mypay: Float)
        {
            rate = load1 + load2
            print("Sus \(userSettings.gp)")
        }
        func move(from source : IndexSet, to destination : Int)
        {
            taskStore.tasks.move(fromOffsets: source, toOffset: destination)
        }
        func delete(at offsets : IndexSet) {
            if let index = offsets.first {  //<-- Here
                let task = taskStore.tasks[index]
                userSettings.gp -= task.amount
            }
            taskStore.tasks.remove(atOffsets: offsets)
        }
    }
    
    struct Final: View {
        @EnvironmentObject var userSettings: UserSettings
        var body: some View {
            Text("Final result \(userSettings.gp)")
        }
    }

Another part of the file is as below:

import Foundation
import SwiftUI
import Combine
class UserSettings: ObservableObject
{
@Published var gp : Float = 0
    
}

struct Task : Identifiable {
    var id = String()
    var toDoItem = String()
    var amount : Float = 0 //<-- Here
}

class TaskStore : ObservableObject {
    @Published var tasks = [Task]()
}

1 Answer 1

3

To use your UserSettings ObservableObject, you need to declare it before you call the Calculation view. Pass it to Calculation using .environmentObject(userSettings) so that it is available in Calculation and all "sub views" (like Final), such as in this example code:

struct ContentView: View {
    @StateObject var userSettings = UserSettings()   // <-- here
    
    var body: some View {
        Calculation().environmentObject(userSettings)  // <-- here
    }
}

EDIT-1: here is the full test code I used:

import SwiftUI

@main
struct TestApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}


struct ContentView: View {
    @StateObject var userSettings = UserSettings()   // <-- here
    
    var body: some View {
        Calculation().environmentObject(userSettings)  // <-- here
    }
}

struct Calculation: View {
    
    @State var load1 = Float()
    @State var load2 = Float()
    @State var rate: Float = 0
    @StateObject var taskStore = TaskStore()  // <-- here
    
    @EnvironmentObject var userSettings: UserSettings
    
    func addNewToDo() {
        taskStore.tasks.append(Task(id: String(taskStore.tasks.count + 1), toDoItem: " Earning: =  \(rate.description)", amount: rate))
    }
    
    var body: some View {
        NavigationView {
            VStack {
                List {
                    Section(header:Text("load 2")){
                        TextField("Enter value of load 1", value: $load1, format: .number)
                        TextField("Enter value of load 1", value: $load2, format: .number)
                    }
                    
                    HStack {
                        Button(String(format: "Add Load"), action: {
                            print("pay for the shift is ")
                            print(Rocky(mypay: rate))
                            userSettings.gp += rate
                        })
                        
                        Button(action: {
                            addNewToDo()
                            Rocky(mypay: rate)
                        },
                               label: {
                            Text(" ")
                        })
                    }
                    
                    ForEach(self.taskStore.tasks) { task in
                        Text(task.toDoItem)
                    }
                    .onMove(perform : self.move)
                    .onDelete(perform : self.delete) //For each
                    
                }
                .navigationBarTitle("SHIFTS")
                .navigationBarItems(trailing: EditButton()) //List
                
                Text("Gross Pay = $\(userSettings.gp) ")
                NavigationLink(destination: Final(), label: {Text("Next")})
            }.onAppear()
            
        }
    }
    
    func Rocky(mypay: Float){
        rate = load1 + load2
        print("Sus \(userSettings.gp)")
    }
    
    func move(from source : IndexSet, to destination : Int){
        taskStore.tasks.move(fromOffsets: source, toOffset: destination)
    }
    
    func delete(at offsets : IndexSet) {
        if let index = offsets.first {  //<-- Here
            let task = taskStore.tasks[index]
            userSettings.gp -= task.amount
        }
        taskStore.tasks.remove(atOffsets: offsets)
    }
}

struct Final: View {
    @EnvironmentObject var userSettings: UserSettings
    var body: some View {
        Text("Final result \(userSettings.gp)")
    }
}


class UserSettings: ObservableObject {
    @Published var gp : Float = 0
}

struct Task : Identifiable {
    var id = String()
    var toDoItem = String()
    var amount : Float = 0 //<-- Here
}

class TaskStore : ObservableObject {
    @Published var tasks = [Task]()
}
Sign up to request clarification or add additional context in comments.

5 Comments

Sorry, I am not able to understand. Can you please help me run the above program where I can view the value of gp in another view as well and the list shows up too. If you run the above program with gp as a @State var, it works fine. However, when you declare gp as an environment object, everything works fine however, the list doesn't appear when you click Add load button. Thanks
updated my answer with the full code I use to show that you can use userSettings.gp in Final view and in Calculation using the approach I outlined.
Note: to add a new Task to taskStore when you click the button, use @StateObject var taskStore = TaskStore() instead of @ObservedObject var taskStore = TaskStore()
But the list still doesn't appear when you click on the Add Load Button. You can check the list appears fine when you declare gp as @State var in Calculation().
Thank you for your help. I can get it worked using the StateObject instead of ObservedObject for taskStore. Thanks mate.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.