userdefaults not being saved after first time - ios

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.

Related

set value in UserDefaults synchronously

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

How to save the state of the stepper in iOS?

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.

UserDefault return different values

I have a very weird problem in Swift3. I want to keep an user logged into application after he has already authenticated in his last session.
My problem is that UserDefaults return sometimes true, sometimes false even if is logged in his account. The problem makes me crazy. I use an bool value stored in UserDefaults, I tried to save a specific string but the problem persist.
Anyone had this problem? Any solutions?
Here is the code when I log in:
UserDefaults.standard.set(true, forKey: LOGIN)
And this is my code in AppDelegate in didFinishLaunchingWithOptions method:
if UserDefaults.standard.bool(forKey: LOGIN) {
AppData().updateUserInformation()
}
I suggest calling UserDefaults.standard.synchronize() after setting UserDefaults values. A lot of developers say that you don't need to do this and that iOS will take care of it for you.
But I've found that not always to be the case, especially when reading values shortly after setting them, or if the app exits before they are synchronized and therefore are lost.

How to save entered data to make it available after app restart

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)")
}

Removing a key from NSUserDefaults not working

I have a logout function in my app. Seems to be a weird problem where it doesn't save the NSUserDefaults. Here I simply want to remove the key. However after logging out if I then open the app again it will find that this key is still in the NSUserDefaults.
func didLogout() {
// Clear user data
let settings = NSUserDefaults.standardUserDefaults()
settings.removeObjectForKey("userData")
settings.synchronize()
unregisterForRemoteNotifications()
openLoginScreen()
}
Any ideas what I could be doing wrong here?
try this
DispatchQueue.main.async {
UserDefaults.standard.removeObject(forKey: YOUR_KEY_HERE)
}
helped for me
removeObjectForKey(_:)
Removing a default has no effect on the value returned by the
objectForKey: method if the same key exists in a domain that precedes
the standard application domain in the search list.
Just use another key instead of userData. It might exists in another domain.
The code above is correct. The key will be still there, but it will return only nil value. So, when user logout you can set
NSUserDefaults.standardUserDefaults().removeObjectForKey("userData")
and when new user login you can set new value by checking
if NSUserDefaults.standardUserDefaults().objectForKey("userData") == nil
One of our (XCTest) unit tests was failing every other run. It turned out that -removeObjectForKey: was — inexplicably — only working every other run. I verified this with defaults.dictionaryRepresentation before and after -removeObjectForKey:. I thought perhaps the keys were being added to two domains and the first remove wasn't getting them both (the docs say this can happen) so I cleverly added a second remove, but that also had no effect. My solution was to set the key to the uninitialized value instead.
Any ideas?
There is no issue in your above code you might have set data in app delegate or when you login your app, or you have mistyped key value.
If you want to clear all data. This will Work
let appDomain = NSBundle.mainBundle().bundleIdentifier!
NSUserDefaults.standardUserDefaults().removePersistentDomainForName(appDomain)
I did the following to delete the userdefault of the app on user loggout
private static let userDefaults = NSUserDefaults.standardUserDefaults()
private static let userTokenKey = "userTokenKey"
userDefaults.removeObjectForKey(userTokenKey)
userDefaults.synchronize()

Resources