What would be the best logic for updating a file periodically after an app has been released

I have a code that needs to be ran about every year to update some files at the app launch and I'm trying to come up with the best way to do that. What I need to be able to basically force the app to run the code whenever I need to update the files.

This is what I came up with that I think would work but I'm not sure if that's the best way.

Are there any other options to handle this type of logic?

App version 1 - INITIAL RELASE.

This code would work as long as I don't add an update.

// First launch
@main
struct SwifUIPlayGroundApp: App {
    
    @AppStorage("shouldLoad") var shouldLoad = true
        
    init(){
        if shouldLoad{
            print("Loading...")
            shouldLoad = false
        }else{
            print("No need to relaod...")
        }
    }
}

App version 2 - UPDATE 1.

Here I would need to add a second variable to force the update shouldUpdate. I would also need to change the logic to check for the shouldUpdate instead of the shouldLoad and set the shouldLoad to true to be prepared for future updates.

// UPDATE 1
@main
struct SwifUIPlayGroundApp: App {

    @AppStorage("shouldUpdate") var shouldUpdate = true // new
    @AppStorage("shouldLoad") var shouldLoad = true
    
    init(){
        if shouldUpdate{
            print("Loading...")
            shouldUpdate = false
            shouldLoad = true // prepare for next update
        }else{
            print("No need to relaod...")
        }
    }
}

App version 3 - UPDATE 2.

Here I would need to change the logic back to check for the shouldLoad instead of the shouldUpdate and set the shouldUpdate to true to be prepared for future updates.

// UPDATE 2
@main
struct SwifUIPlayGroundApp: App {

    @AppStorage("shouldUpdate") var shouldUpdate = true
    @AppStorage("shouldLoad") var shouldLoad = true
    
    init(){
        if shouldLoad{
            print("Loading...")
            shouldUpdate = true // prepare for next update
            shouldLoad = false 
        }else{
            print("No need to relaod...")
        }
    }
}

App version 4 - UPDATE 3.

Repeat what I did in UPDATE 1...

Accepted Reply

So everything occurs in the app. Right ?

Which means user has first to upgrade to new release for anything to happen. Right ?

If so, why not having a flag in the JSON, which tracks that file Has Changed Since Previous Version ?

And reload CoreData if true.

However, if user skips an update, flag may be false… even though user should update.

So, may be the best is to not have a Bool flag but a version number flag, indicating when file last changed. Comparing to last version on the device (kept in AppStorage), you know if you have to load or not.

And when the app is first installed, nothing in AppStorage yet (or just a version 0 by default, so that comparison triggers the load); so you know you have to load Coredata.

Replies

Let's assume you update the file on the 1st Jan each year.

I would use 3 dates:

  • lastUpdate, saved in AppStorage each time the file is updated
  • today, when the app launches
  • a computed var, JanFirst, 1st Jan of the year of today.

Then, at launch, you compare:

  • if lastUpdate < janFirst, that means there is an update pending
  • then you update file and update lastUpdate

So for instance:

  • lastUpdate = 2022 Feb 10
  • today = 2023 Jan 2
  • then janFirst = 2023 Jan 1

-> You have to update

if you had launched on 2022 Dec 10:

  • today = 2022 Dec 10
  • janFirst = 2022 Jan 1

-> There was no need to update when launching on Dec 10.

But there may be a simpler solution, which does not force to update the file on server at fixed date:

  • save the last update version number in AppStorage
  • at launch, check on server the last version number
  • update if needed.

You could use a stored lastUpdated date and compare it on each launch:

@main

struct SwifUIPlayGroundApp: App {

    @AppStorage("lastUpdated") var lastUpdated = Date()

    private var shouldUpdate: Bool {
        let now = Date()
        let hoursInYear = 8760

        guard let hoursPassed = Calendar.current.dateComponents([.hour], from: lastUpdated, to: now).hour else { return false }

        return hoursPassed >= hoursInYear
    }

    init() {
        if shouldUpdate {
            lastUpdated = Date() // Set it to now
            print("Loading...")
        } else {
            print("No need to relaod...")
        }
    }
}

Thanks a lot for the good ideas. The one thing I don't think I was clear on, was the fact that the update will always be triggered manually and will be followed by a new AppStore submission. I'll basically decide in what app version/release I want to run the update. In other words, the update could happen sooner than a year. What I was thinking is something like my first example but with the ability to be able to manually forece-change the shouldLoad variable to true for all users, existing and new at any point. Again, the update would need to happen to all users, and new users do not need to know about the original content in the file as long as the latest is loaded.

Not sure to understand.

  • the file is included in the app update, it is not an independent file on your server ?
  • If so, you want users to know that a new update is available. But how could the old version know without consulting on your server (or on appstore to check if new version available).

Could you detail a use case, steps by step ?

Yes, the file is included in the app update, it's not in the server. The user doesn't need to know as long as they get the latest file released in the latest app version.

I have a JSON that is included in the app. At the first app launch, it will be read and load all of its content to Core Data. Now, if later on the JSON file gets new info and needs to update Core Data I would like to reload the entire JSON file. And again, this will be done in a new app release.

I can do it the way I showed it in my original post or use new variables to check against every time there is an update, but I don't really like it. I was wondering if there is a way to overwrite the shouldLoad variable to true to make it look as if it was the first app launch even for existing users. I hope it starts making sense. Thanks a lot for following along.

So everything occurs in the app. Right ?

Which means user has first to upgrade to new release for anything to happen. Right ?

If so, why not having a flag in the JSON, which tracks that file Has Changed Since Previous Version ?

And reload CoreData if true.

However, if user skips an update, flag may be false… even though user should update.

So, may be the best is to not have a Bool flag but a version number flag, indicating when file last changed. Comparing to last version on the device (kept in AppStorage), you know if you have to load or not.

And when the app is first installed, nothing in AppStorage yet (or just a version 0 by default, so that comparison triggers the load); so you know you have to load Coredata.

Yes, everything occurs in the app. The user doesn't have to do anything except update the app to the new version, otherwise, he can continue using the app with the old file. I really like the idea of having a flag in the JSON file.

Something like, if flagInJSONFile != lastSavedInUserDefaultsVariable{ updateFile()}

In the JSON file I could name the flag, update2023 then overwrite it next year or the next update to something like update2024.

if update2023 != update2024{updateFile()}

Thanks a lot for the good ideas.