LAST CHANCE: Save 50% on all my Swift books and bundles! >>

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      

Hacking with Swift is sponsored by Essential Developer.

SPONSORED Join a FREE crash course for mid/senior iOS devs who want to achieve an expert level of technical and practical skills – it’s the fast track to being a complete senior developer! Hurry up because it'll be available only until July 28th.

Click to save your free spot now

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.