'Data changes only after closing the app in the background in SwiftUI

I´m using core data to safe date in my iOS app. On button click I safe data to core data. In a separate tab the data is used in computed properties to get averages out of the added values and display them to the view. This works but the data only updates after the app is closed in the background. I've tried to pass the data into a viewModel and pass the data with an Environment Object but that didn't work (Sorry if this isn't very precise, that's my first post).

import SwiftUI

struct HabitStatistics: View {

    @Environment(\.managedObjectContext) private var viewContext

    @FetchRequest(sortDescriptors: []) var habits: FetchedResults<Habit>

        // MARK: Computing EarlyBird Property
        var filteredEarlyBird: Int {
            var earlyBird = 0
            var counter = 0
            for h in habits {
                let component = Calendar.current.dateComponents([.hour, .minute], from: h.getUpTime ?? Date())
                let hour = component.hour ?? 0
                let minute = component.minute ?? 0
                let difference = (hour * 60 + minute) - 270
                earlyBird += difference
                counter += 1
            }
            if counter != 0 {
                earlyBird /= counter
                return earlyBird
            } else {
                return 0
            }
        }

            // MARK: Computing ateMeat Property
        var filteredMeat: Int {
            var total: Int {
                if habits.count == 0 {
                    return 1
                } else {
                    return habits.count
                }
            }
            var count = 0
            var perc = 0
            for h in habits {
                if h.ateMeat == 0 {
                    count += 1
                }
            }
            perc = count * 100 / total
            return perc
        }

            // MARK: Computing ateSuger Property
        var filteredSugar: Int {
            var total: Int {
                if habits.count == 0 {
                    return 1
                } else {
                    return habits.count
                }
            }
            var count = 0
            var perc = 0
            for h in habits {
                if h.ateSugar == 0 {
                    count += 1
                }
            }
            perc = count * 100 / total
            return perc
        }

            // MARK: Computing didSports Property
        var filteredSport: Int {
            var total: Int {
                if habits.count == 0 {
                    return 1
                } else {
                    return habits.count
                }
            }
            var count = 0
            var perc = 0
            for h in habits {
                if h.didSports == 1 {
                    count += 1
                }
            }
            perc = count * 100 / total
            return perc
        }

    var body: some View {

        VStack(alignment: .leading, spacing: 0) {
                // Headline
            Text("This Week")
                .bold()
            VStack {
                RectangleCard(textLeft: "Meatfree", textRight: "\(filteredMeat) %")
                RectangleCard(textLeft: "Sugarfree", textRight: "\(filteredSugar) %")
                RectangleCard(textLeft: "Sportsrate", textRight: "\(filteredSport)%")
                RectangleCard(textLeft: "Average Time Loss", textRight: "\(filteredEarlyBird) Min lost")
                
            }
        }
     
    }
}


import SwiftUI
struct DailyForm: View {

    @Environment(\.managedObjectContext) private var viewContext
    @EnvironmentObject var model: HabitModel

    

    @State var getUpTime = Date()
    @State var ateMeat = InputOptions.nein
    @State var ateSugar = InputOptions.nein
    @State var didSports = InputOptions.nein



    var body: some View {

        VStack {
            HStack {
                Button("Clear") {
                    clear()
                }
                Spacer()
                Button("Add") {
                    addHabit()
                    clear()
                }
                
            }
            .padding()

            ScrollView (showsIndicators: false) {

                VStack (alignment: .leading) {
                    AddPickerValues(getUpTime: $getUpTime,
                                    ateMeat: $ateMeat,
                                    ateSugar: $ateSugar,
                                    didSports: $didSports)
                }
                .padding(.horizontal)
            }

        }
    }

    func clear() {
        getUpTime = Date()
        ateMeat = InputOptions.nein
        ateSugar = InputOptions.nein
        didSports = InputOptions.nein
    }

    func addHabit() {
        let habit = Habit(context: viewContext)
        habit.id = UUID()
        habit.getUpTime = getUpTime
        habit.ateMeat = convertValue(habit: ateMeat)
        habit.ateSugar = convertValue(habit: ateSugar)
        habit.didSports = convertValue(habit: didSports)

        do {
            try viewContext.save()
        }
        catch {
                // Couldn't save the recipe
        }
    }

    func convertValue (habit: InputOptions) -> Int {
        if habit == InputOptions.nein {
            return 0
        } else {
            return 1
        }
    }
}


Solution 1:[1]

This is working:

Main:

@main
struct coretatatestApp: App {
    let persistenceController = PersistenceController.shared
    
    var body: some Scene {
        WindowGroup {
            TabView {
                DailyForm()
                    .tabItem {
                        Label("Daily Form", systemImage: "calendar" )
                    }
                HabitStatistics()
                    .tabItem {
                        Label("Statistics", systemImage: "chart.bar.fill" )
                    }
            }
            .environment(\.managedObjectContext, persistenceController.container.viewContext)
        }
    }
}

Statistics:

struct HabitStatistics: View {
    
    @Environment(\.managedObjectContext) private var viewContext
    
    @FetchRequest(sortDescriptors: []) var habits: FetchedResults<Habit>
    
    // MARK: Computing EarlyBird Property
    var filteredEarlyBird: Int {
        var earlyBird = 0
        var counter = 0
        for h in habits {
            let component = Calendar.current.dateComponents([.hour, .minute], from: h.getUpTime ?? Date())
            let hour = component.hour ?? 0
            let minute = component.minute ?? 0
            let difference = (hour * 60 + minute) - 270
            earlyBird += difference
            counter += 1
        }
        if counter != 0 {
            earlyBird /= counter
            return earlyBird
        } else {
            return 0
        }
    }
    
    // MARK: Computing ateMeat Property
    var filteredMeat: Int {
        var total: Int {
            if habits.count == 0 {
                return 1
            } else {
                return habits.count
            }
        }
        var count = 0
        var perc = 0
        for h in habits {
            if h.ateMeat == false {
                count += 1
            }
        }
        perc = count * 100 / total
        return perc
    }
    
    // MARK: Computing ateSuger Property
    var filteredSugar: Int {
        var total: Int {
            if habits.count == 0 {
                return 1
            } else {
                return habits.count
            }
        }
        var count = 0
        var perc = 0
        for h in habits {
            if h.ateSugar == false {
                count += 1
            }
        }
        perc = count * 100 / total
        return perc
    }
    
    // MARK: Computing didSports Property
    var filteredSport: Int {
        var total: Int {
            if habits.count == 0 {
                return 1
            } else {
                return habits.count
            }
        }
        var count = 0
        var perc = 0
        for h in habits {
            if h.didSports == true {
                count += 1
            }
        }
        perc = count * 100 / total
        return perc
    }
    
    var body: some View {
        VStack(alignment: .leading, spacing: 0) {
            // Headline
            Text("This Week")
                .bold()
            VStack {
                Text("Meatfree \(filteredMeat) %")
                     Text("Sugarfree \(filteredSugar) %")
                     Text("Sportsrate \(filteredSport)%")
                     Text("Average Time Loss \(filteredEarlyBird) Min lost")
            }
        }
    }
}

Daily Form:

struct DailyForm: View {
    
    @Environment(\.managedObjectContext) private var viewContext
//    @EnvironmentObject var model: HabitModel
    @FetchRequest(sortDescriptors: []) var habits: FetchedResults<Habit>

    
    @State var getUpTime = Date()
    @State var ateMeat = false
    @State var ateSugar = false
    @State var didSports = false
    
    
    var body: some View {
        
        VStack {
            HStack {
                Button("Clear") {
                    clear()
                }
                Spacer()
                Button("Add") {
                    addHabit()
                    clear()
                }
                
            }
            .padding()
            
            ScrollView (showsIndicators: false) {
                
                VStack (alignment: .leading) {
                    DatePicker("Get up Time", selection: $getUpTime, displayedComponents: .hourAndMinute)
                    Toggle("Ate Meat?", isOn: $ateMeat)
                    Toggle("Ate Sugar?", isOn: $ateSugar)
                    Toggle("Did Sports?", isOn: $didSports)
                }
                .padding(.horizontal)
            }
            
        }
    }
    
    func clear() {
        getUpTime = Date()
        ateMeat = false
        ateSugar = false
        didSports = false
    }
    
    func addHabit() {
        let habit = Habit(context: viewContext)
        habit.id = UUID()
        habit.getUpTime = getUpTime
        habit.ateMeat = ateMeat
        habit.ateSugar = ateSugar
        habit.didSports = didSports
        
        do {
            try viewContext.save()
        }
        catch {
            // Couldn't save the recipe
        }
    }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 ChrisR