BLACK FRIDAY: Save 50% on all my Swift books and bundles! >>

Refreshing a list over time

Forums > SwiftUI

Hi,

I have a list that displays it's data from SwiftData. One of the items displayed is the number of days until a date stored in the model. It all seems to work fine except if you open the app the next day the number of days shown is incorrect as the data hasn't changed the today's date has.

Currently I have to force quit the app and open it again.

I can only think of a hacky way of solving this using a timer and updating a number in a ZStack than you cannot see but this obviously isn't the correct thing to do.

Can anyone give me some guidance on the correct way of tackling this please

I don't really want to have dirty hacks in the code.

Thanks in advance,

Gareth

   

Am disappointed you didn't include code. How can we help you if we don't see what you did?

Your SwiftData model doesn't have to only indicate what elements to store. It's a Swift class. I think you should consider adding business logic to your class.

Here's a sample I wrote to illustrate the concept.

@Observable
class ActionItem {
    var description: String = "Finish SwiftUI App"
    var actionDate:  Date   = Date.now
    // This variable is calculated, not stored in SwiftData
    // When the actionDate changes, so does the daysToGo value.
    var daysToGo:    Int {
        return daysBetween( nowAnd: actionDate) ?? 0
    }

    // This is a convenience function to help you determine
    // the number of days between two dates.
    private func daysBetween(nowAnd endDate: Date) -> Int? {
        let calendar   = Calendar.current
        let startOfDay = calendar.startOfDay(for: Date.now )
        let endOfDay   = calendar.startOfDay(for: endDate  ) 
        let components = calendar.dateComponents([.day], from: startOfDay, to: endOfDay)

        // return the number of days to go if due date is in the future.
        // if due date is in the past, just return 0
        return components.day! > 0 ? components.day : 0
    }

    // This is a convenience function for the view's buttons to call.
    // This business logic belongs in the ActionItem class.
    // It does NOT belong in the view!
    public func adjustDueDateBy(_ daysToAdjust: Int) {
        let calendar   = Calendar.current
        let components = DateComponents(day: daysToAdjust)
        actionDate     = calendar.date(byAdding: components, to: actionDate) ?? Date.now
    }
}

struct ActionItemView: View {
    // Create an action item
    // Any time something in this object changes, update this view!
    @State var actionItem = ActionItem()

    var body: some View {
        VStack {
            Text(actionItem.description).font(.largeTitle).padding(.bottom)
            Text("Today: \(Date.now.formatted(date: .abbreviated, time: .omitted))")
            Text("Due Date: \(actionItem.actionDate.formatted(date: .abbreviated, time: .omitted))")
                .padding(.bottom)
            Text("Due in: \(actionItem.daysToGo) days").font(.title)
                .padding(.bottom)
            // Adjust the Due Date plus or minus 5 days
            HStack {
                // Tell the class what action to take.
                Button("+ 5") { actionItem.adjustDueDateBy( 5 ) }
                Button("- 5") { actionItem.adjustDueDateBy(-5 ) }
            }
        }
    }
}

Keep Coding!

Next time, help us to help you! Please include code snips along with inline comments explaining what you're trying to accomplish.

PS: It's means "it is" or "it has"

   

Thanks,

I'll have a play around with my code.

   

hi Gareth,

One of the items displayed is the number of days until ... if you open the app the next day the number of days shown is incorrect as the data hasn't changed the today's date has

i'll try something different, since i think you're asking for help wih a slightly different question than @Obelix addresses.

if your app goes into the background (e.g., you move to another), whatever screen you looked at previously in your app will be brought forward when you switch back to the app, but it will not update automatically.

in your case, your sense of "what is today" when counting days until completion will be different if you come back to your app on another day.

you can track when your app moves from active to inactive at the (SwiftUI) App object, and if you have some form of an observable "Today" object in your app's enviroment, you can update that value upon a change from inactive to active; and if your views reference the "Today" object when determining "how many days until", they will be updated for you when returning to the active state.

i have an example of exactly this in my shopping list app on GitHub ... it should not be hard to import. you'll find most of what you need in the App object.

just be sure that views always reference this "Today" object when counting rather than using Date.now(), which i am guessing is what you did.

hope that helps,

DMG

   

Thank you DMG this is very helpful.

   

Save 50% in my WWDC sale.

SAVE 50% All our books and bundles are half price for Black Friday, so you can take your Swift knowledge further without spending big! Get the Swift Power Pack to build your iOS career faster, get the Swift Platform Pack to builds apps for macOS, watchOS, and beyond, or get the Swift Plus Pack to learn advanced design patterns, testing skills, and more.

Save 50% on all our books and bundles!

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.