UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

SOLVED - Day 47 Challenge - count not updating in real time

Forums > 100 Days of SwiftUI

Hi, new forum member here, although I'm on Day 47 of the program. I've got the habit tracker working to a point. I can add a habit, see the detail view, and increase the number of times it is completed, but I don't see the count increase when I tap the button. I have to leave the detail view and then open it again to see the increased count. I assume it must have something to do with how I'm managing state, but I guess I don't fully understand all the concepts yet. Any help would be appreciated.

UPDATE: I used a LazyVGrid instead of this complicated custom grid layout and it just worked.

ContentView:

import SwiftUI

struct HabitItem: Identifiable, Codable, Equatable {
    var id = UUID()
    let name: String
    let description: String
    var completed: Int
}

@Observable
class Habits {
    var items = [HabitItem]() {
        didSet {
            if let encoded = try? JSONEncoder().encode(items) {
                UserDefaults.standard.set(encoded, forKey: "Items")
            }
        }
    }

    init() {
        if let savedItems = UserDefaults.standard.data(forKey: "Items") {
            if let decodedItems = try? JSONDecoder().decode([HabitItem].self, from: savedItems) {
                items = decodedItems
                return
            }
        }

        items = []
    }
}

struct ContentView: View {
    @State private var habits = Habits()
    @State private var showingAddHabit = false

    var body: some View {
        NavigationStack {
            List {
                ForEach(habits.items) { item in
                    NavigationLink {
                        HabitView(habits: habits, habit: item)
                    } label: {
                        HStack {
                            VStack(alignment: .leading) {
                                Text(item.name)
                                    .font(.headline)
                            }
                        }
                    }
                }
            }
            .navigationTitle("Habit Tracker")
            Button("Add a Habit to Track") {
                showingAddHabit = true
            }
            .buttonStyle(.borderedProminent)
            .controlSize(.large)
        }
        .sheet(isPresented: $showingAddHabit) {
            AddHabitView(habits: habits)
        }
    }
}

#Preview {
    ContentView()
}

And HabitView

import SwiftUI

struct HabitView: View {
    var habits = Habits()
    let habit: HabitItem
    @State var numCells: (Int, Int)

    init(habits: Habits = Habits(), habit: HabitItem) {
        self.habits = habits
        self.habit = habit
        _numCells = State(initialValue: habit.completed.quotientAndRemainder(dividingBy: 20))
    }

    var body: some View {
        Text(habit.name)
            .font(.largeTitle)
        Text(habit.description)
        ScrollView {
            Grid {
                ForEach(0..<numCells.0 + 1, id: \.self) {number in
                    GridRow {
                        if number + 1 == numCells.0 + 1 {
                            ForEach(0..<numCells.1) {cell in
                                Rectangle()
                                    .frame(width: 10, height: 10)
                                    .foregroundColor(/*@START_MENU_TOKEN@*/.blue/*@END_MENU_TOKEN@*/)
                            }
                        } else {
                            ForEach(0..<20) {cell in
                                Rectangle()
                                    .frame(width: 10, height: 10)
                                    .foregroundColor(/*@START_MENU_TOKEN@*/.blue/*@END_MENU_TOKEN@*/)
                            }
                        }
                    }
                }
            }
        }
        Button("Did It") {
            var tempHabit = habit
            tempHabit.completed += 1
            if let index = habits.items.firstIndex(of: habit) {
              habits.items[index] = tempHabit  // index is not optional any more
            }
        }
        .buttonStyle(.borderedProminent)
    }
}

#Preview {
    HabitView(habit: HabitItem(id: UUID(), name: "Name", description: "Foo", completed: 257))
}

2      

BUILD THE ULTIMATE PORTFOLIO APP Most Swift tutorials help you solve one specific problem, but in my Ultimate Portfolio App series I show you how to get all the best practices into a single app: architecture, testing, performance, accessibility, localization, project organization, and so much more, all while building a SwiftUI app that works on iOS, macOS and watchOS.

Get it on Hacking with Swift+

Sponsor Hacking with Swift and reach the world's largest Swift community!

Reply to this topic…

You need to create an account or log in to reply.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.