I'm using UserDefaults with SwiftUI to save my data from multiple variables and I use them for graphs which shows some daily information. Is there a way to delete or reset the saved data form UserDefaults to only contain the data form the current day?
For example delete the data at 23:59 every night.
#Published var waterGraph: Float = UserDefaults.standard.float(forKey: "waterGraph") {
didSet {
UserDefaults.standard.set(self.waterGraph, forKey: "waterGraph")
}
}
Do you really need to delete the data from your UserDefaults at exactly 23:59? If you do then you would have to run background tasks which can be quite complicated. Another easier alternative is to clear the UserDefaults each time the user opens the app and if it has been 24 hours since your UserDefaults data was stored. Store a value in your UserDefaults called "in24hours" and set its value to 24 hours from the current time. In the appDelegate's didFinishLaunchingWithOptions function, check for the date stored in the userDefaults "in24hours" and if the current time is greater than the time in that variable, then you can clear your userDefaults there. You can set the "in24hours" variable whenever you want (after you add your to be deleted data in UserDefaults). Instead of setting the "in24Hours" to 24 hours from the current time and date, you could also set it to midnight on the following date.
Related
I am trying to save boolean in UserDefault in swift.
so when I set value in userDefault, my very next instruction is to switch to view controller and close the current view controller.
so, what is happening now is, sometimes userDefault saves the value in DB, and sometimes it doesn't.
I read documentation from Apple
https://developer.apple.com/documentation/foundation/userdefaults
and found that
At runtime, you use UserDefaults objects to read the defaults that your app uses from a user’s defaults database. UserDefaults caches the information to avoid having to open the user’s defaults database each time you need a default value. When you set a default value, it’s changed synchronously within your process, and asynchronously to persistent storage and other processes.
so, I guess because in the very next line I open a new controller and close the current one so due to which there is inconsistency.
here is my code
func setWalkthroughShown(completionHandler: #escaping ()->()) {
UserDefaults.standard.set(true, forKey: isWalkthroughCompleted)
UserDefaults.standard.synchronize()
completionHandler()
}
I even called UserDefaults.standard.synchronize() so that operation may become synchronous.
even though in the documentation it is clearly written not to use this function.
can someone please guide me where I am wrong? how can I save across all places before closing the current process?
this is the function by which I am retrieving value
func isWalkthroughShown() -> Bool {
return UserDefaults.standard.bool(forKey: isWalkthroughCompleted)
}
here isWalkthroughCompleted is a string and you can see I am using same string for saving and retrieving value
Actually, there was no syntax error in coding.
I was actually testing it in the wrong way.
after submitting for the request of saving data in userdefaults, I was recompiling immediately and as value stores asynchronously so sometimes due to killing of the process I was getting this issue.
thanks to #matt.
for detail iOS UserDefaults falls behind saved content
I’m doing an app to be used as an inventory.
I need to know how to save the state of the stepper
So if I or another user close the app, the state of the stepper won’t change.
My app is targeting multiple users, so if one user has changed the stepper state it will be saved and changed for other users.
The main idea: save UIStepper's value.
It depends on your needs how you should save it:
If you have just one main stepper and this is the whole idea of your
app, you can save value to UserDefaults and then retrieve it
let stepper = UIStepper()
// Saving
UserDefaults.standard.set(stepper.value, forKey: "stepperValue")
// Retrieving
stepper.value = UserDefaults.standard.double(forKey: "stepperValue")
If you have various number of steppers and their values are also connected with some model, you should use FileManager to save encoded values of steppers or you can also use some database like CoreData or Realm.
I created some simple system that if userdefaults have key "isWalkthroughPresented". If the key is false then show walkthourghViewController. If it doesn't have the key then check from database.
However it doesn't set the key after first time. But saves after some launches. What should be the problem?
This is the code I use inside viewDidAppear after user has signed in and sees second ViewController:
let userDefaults = UserDefaults.standard
if !userDefaults.bool(forKey: "isWalkthroughPresented") {
presentWalkthrough()
userDefaults.set(true, forKey: "isWalkthroughPresented")
}else{
checkIfCurrentUserHasOpenedTheAppBefore()//this just checks if user in db has the value
}
After setting the user defaults value, call this to force saving the changes to database:
//...
userDefaults.set(true, forKey: "isWalkthroughPresented")
userDefaults.synchronize()
Normally the synchronize() method is called periodically to save the cached user settings to database. The interval between you set the "isWalkthroughPresented" and read it again is not enough to synchronize() get automatically called.
See also these details from the method documentation:
Because this method [synchronize()] is automatically invoked at periodic intervals, use this method only if you cannot wait for the automatic synchronization (for example, if your application is about to exit) or if you want to update the user defaults to what is on disk even though you have not made any changes.
I'm I obliged to pass either UIApplicationBackgroundFetchIntervalMinimum or UIApplicationBackgroundFetchIntervalNever ?
Or Is it possible to pass a custom interval instead, for example 10 minutes:
UIApplication.sharedApplication().setMinimumBackgroundFetchInterval(600.0)
In my App, I have to download some new updated data while the app is in the background.
Then I'll use the new data to send a local notification to the user.
I looked up apis and found this:
func setMinimumBackgroundFetchInterval(_ minimumBackgroundFetchInterval: NSTimeInterval)
And there is a tip for this:
The minimum number of seconds that must elapse before another
background fetch can be initiated. This value is advisory only and
does not indicate the exact amount of time expected between fetch
operations.
So I think you'd better not depend on that time interval.
I have my own custom data structures which receive input through the ViewController class. The interface is a simple text field, which is linked to a variable that the contents of the text field is copied to. Upon launching the app, the text field should be prepopulated with data entered in the past. However, as soon as I close the app, the data is lost. I am new to programming and assume this can be remedied by implementing the necessary functions in AppDelegate class, more specifically, under the default applicationWillTerminate function. If this is correct, how do I implement the data saving process? If not, where & how do I make sure data entered is stored so that fields are prepopulated the next time the app is opened?
If you need to store small amount of data, take a look at NSUserDefaults.
If your data better fits to a database, you can use SQLite (may be with a wrapper) or Core Data.
There is also a modern but not yet very mature cross-platform mobile database called Realm (partially open-sourced at the moment).
Since you are saving TextField data(which use mostly small string text) Use NSUserDefaults to store the string for persistence. What you need to do is at textFieldEndEditing save the text to NSUserDefaults and in viewDidLoad assign it to textField.
Saving To NSUserDefaults:
let defaults = NSUserDefaults.standardUserDefaults()
defaults.setObject(myTextField.text, forKey: "TextFieldText")
defaults.synchronize()
Retrieving from NSUserDefaults:
let defaults = NSUserDefaults.standardUserDefaults()
if let savedText = defaults.stringForKey("TextFieldText")
{
print("Textfield Text: \(savedText)")
}