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

SOLVED: Milestone: Projects 7-9, issue updating value

Forums > 100 Days of SwiftUI

Hello!

I have an issue in the HabitsTracker project app when it comes to update the counter for the habit in its detail view. The structure is as follows:

  • I have an Activities class which conforms to ObservableObject which, in turn, has a @Published var items = [Activity] that is read/written from/to UserDefaults
  • My list view has an @ObservedObject var activities: Activities which is passed from the App struct
  • When it navigates to the detail view, I pass both activities and the selected activity
  • My details view has:
    • @ObservedObject var activities: Activities
    • @State var activity: Activity
    • A button that calls the following method
private func increment() {
    guard let index = activities.items.firstIndex(of: activity) else { return }

    activity.numberOfTimes += 1
    activities.items[index].numberOfTimes = activity.numberOfTimes
}

The problem is:

  • If I press the button once, the numberOfTimes increments by one, its corresponding label shows the updated value and, if I go back to the list view, I can see that the value is also updated correctly. But, if I press it a second time, numberOfTimes is no longer incremented, and the value doesn't change no matter how many times I call the increment method.

Maybe I'm missing something, but I can't understand what's going on. I followed the example in the iExpense app, to no avail.

Can you help me out?

2      

hi,

i have removed my initial response(s) and i'll defer to Patrick's explanation below; i was confused, thinking that activity was a (class) object; apparently it's a struct. i should have recognized that. my apologies for the confusion (which was mine alone).

regards,

DMG

2      

Instead of passing both the Activities class and the individual Activity, you should be passing in a Binding to the Activity so that you can update it in your detail view.

Here's a very simplified example to demonstrate:

import SwiftUI

struct Activity: Identifiable {
    let id = UUID()
    let name: String
    var numberOfTimes: Int = 0
}

class Activities: ObservableObject {
    @Published var activities: [Activity]

    init() {
        activities = [
            Activity(name: "Jogging"),
            Activity(name: "Reading"),
            Activity(name: "Petting the cat"),
        ]
    }
}

struct ContentView: View {
    @StateObject var activities = Activities()

    var body: some View {
        ActivitiesListView(activities: activities)
    }
}

struct ActivitiesListView: View {
    @ObservedObject var activities: Activities

    var body: some View {
        NavigationView {
            List {
                ForEach($activities.activities) { $activity in
                    NavigationLink(destination: ActivityDetailView(activity: $activity)) {
                        HStack {
                            Text(activity.name)
                            Spacer()
                            Text("\(activity.numberOfTimes)")
                        }
                    }
                }
            }
        }
    }
}

struct ActivityDetailView: View {
    @Binding var activity: Activity

    var body: some View {
        VStack(spacing: 40) {
            Text(activity.name)
                .font(.title)
            Text("\(activity.numberOfTimes)")
                .font(.subheadline)
            Button("Increment") {
                activity.numberOfTimes += 1
            }
        }
    }
}

This syntax is available starting in Swift 5.5 and iOS15 but it's backwards compatible to iOS13 as long as you are compiling with Xcode 13.

activities incrementing

3      

@delawaremathguy tried your method (to convert Activity to Class, didn't make it clear it was a Struct), but @roosterboy's approach is exactly what I was looking for.

Thank you both for the help!

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 April 28th.

Click to save your free spot now

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

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

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.