1

I am having a problem with my UserDefault settings not persisting when my app launches. I have read other posts on this matter and most are marked solved after various tips. I have implemented all of the suggested tips (that I am aware of) and I still have this problem.

I have created the simplest sample app. The app has has a button that toggles between Login/Logout depending on the current state of a UserDefault setting called "isLoggedIn."

Here's the code...

import UIKit

class LoginViewController: UIViewController {

    @IBOutlet weak var loginButton: UIButton!

    override func viewDidLoad() {
        super.viewDidLoad()        
    }

    override func viewDidAppear(_ animated: Bool) {
        refreshButton()
    }

    @IBAction func loginButtonPressed(_ sender: UIButton) {
        let isLoggedIn = UserDefaults.standard.bool(forKey: "isLoggedIn")
    
        UserDefaults.standard.set(!isLoggedIn, forKey: "isLoggedIn")
    
        refreshButton()
    }

    func refreshButton() {
        let isLoggedIn = UserDefaults.standard.bool(forKey: "isLoggedIn")
            
        loginButton.setTitle(isLoggedIn ? "Logout" : "Login", for: .normal)
    }

}

When the button is clicked, the UserDefault setting is updated and the button is refreshed to display Login or Logout based on the new setting. If I run the app in the simulator I can see the button toggle which tells me that the UserDefault setting is being stored properly.

The problem occurs when I relaunch the app. The button is refreshed to show the last state of the UserDefault setting when the app was closed. But it doesn't always properly reflect the previous state. Occasionally it does but I more often it does not. I cannot see any pattern here either.

I have tried...

  • Using the set method instead of the setValue method
  • Calling the synchronize method after applying the update (I'm aware that Apple says this is no longer required or suggested)

I just cannot pinpoint what I am overlooking. Does anyone have any ideas about what I am doing wrong? Please let me know if I can provide any additional code that might help.

Thanks, Joel

UPDATE

I decided to track the actual changes to the setting in the plist file itself. Upon inspection, I noticed that the setting was taking several seconds to physically update in the file. Therefore, if I wait for several seconds before closing my app then the setting will save and it will display properly when I launch again. So new question is...

  • Why does it take so long for my setting to save?
  • and can I ensure that the app does not close before the setting is properly saved?

It's funny because I thought that was the purpose of the synchronize method that Apple say not to use anymore.

Thanks again!

Joel S.
  • 41
  • 5

2 Answers2

2
import UIKit

class LoginViewController: UIViewController {
    var isLogin = false
    @IBOutlet weak var loginButton: UIButton!

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        refreshButton()
    }


    @IBAction func loginButtonPressed(_ sender: UIButton) {
        isLogin.toggle()
        UserDefaults.standard.set(isLogin, forKey: "isLoggedIn")
        refreshButton()
    }

    func refreshButton() {
        isLogin = UserDefaults.standard.bool(forKey: "isLoggedIn")
            
        loginButton.setTitle(isLogin ? "Logout" : "Login", for: .normal)
    }

}
Zeeshan Ahmad II
  • 1,047
  • 1
  • 5
  • 9
  • Thanks Zeeshan. I was skeptical to believe that your solution would work since all you are really doing is storing the toggle in a local variable. I tried it with your code and it still doesn't work. Any other suggestions? I noticed the addition of `super.viewWillAppear` in the `ViewWillAppear` function. That makes me wonder if I am missing something and my settings aren't properly loading at startup. Do you know if there is a way to check the value that is stored in the settings file? – Joel S. May 23 '22 at 13:45
  • its working fine bro i have tested it many times – Zeeshan Ahmad II May 24 '22 at 04:43
  • I updated my post yesterday. The reason it's not working is because my settings are not being written to the plist file quickly enough. So often times, I close the app before the value was ever saved. That's why it does not match when I relaunch the app. So the underlying issue was never really the settings not saving. I thought the problem went away when I ran on an actual device but I was wrong. I still have the issue when I run on my tablet or phone. I thought the deprecated `synchronize` method was intended to wait for the settings to finish updating before resuming but they don't. Thanks. – Joel S. May 24 '22 at 11:05
2

There is an explanation for your questions, it is because of the way how UserDefault system works. Usually, it takes time to save your data. You might be losing data during your application development. For example, if you are developing an application with swift, when you changed some codes in your project and launch your app then click the stop button in Xcode, you will probably lose some of the data, because at that moment, some of the data still in the memory waiting for being saved.

But do not worry, it will be saved eventually when your application is published to the users.

By the way, I have tested my project, I install my iOS app on my iPhone without using XCode, and it saves all of the data either I close my app on the tasks list(swipe out) or click the home button and open the app again, the data still there.

Here, hope this article will clear your confusion: Why Do You Lose Data Stored in User Defaults

LouisWong
  • 48
  • 5
  • 1
    light weight objects doesn't take time to save in UserDefaults. If developer trying to save heavy objects in UserDefaults or array of objects rather than using Core data or sqlite table then application loss data. – Zeeshan Ahmad II Jun 14 '22 at 04:57
  • System works concurrently. System have to done multiple task at once so system perform light weight task first so as saving value in UserDefaults is a light weight task. On the other hand the code style also cause problem if you are not using the right way to get and save value as you did above – Zeeshan Ahmad II Jun 14 '22 at 05:02
  • Exactly, UserDefaults should be used to save lightweight data, I would prefer using SQLite to UserDefaults to save data, it's more reliable and robust. – LouisWong Jun 14 '22 at 09:41