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