Search code examples
iosswiftnsuserdefaults

Swift - Set UserDefault if not already set


My intention is to show my InitialViewController only once per user.

The code inside of didFinishLaunchingWithOptions is supposed to check on start whether the value of UserDefaults key firstTime is still true.
If not, it shall not show InitialViewController. If it's true and the VC is being displayed, its button (see 2nd code below) shall set firstTime to false to prevent InitialViewController from being displayed next time the app is started.

I reckon I figured out the problem, namely: defaults.set(true, forKey: "firstTime") inside of didFinishLaunchingWithOptions:
Everytime the app launches, it ignores the fact that the key might have been set to false in a previous start, since it sets it to true anyways.
A possible solution might be to check, whether firstTime has already been set, if so it won't set firstTime again. But I haven't been able to find a possible approach yet. That's where I need your help.
Removing it won't help either, since when the app is started for the first time, it needs this key to exist and to be true to show InitialViewController in the first place.

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

        if let rvc = self.window?.rootViewController {

            let defaults = UserDefaults.standard
            defaults.set(true, forKey: "firstTime")

            if defaults.bool(forKey: "firstTime") == true  {
                let vc = rvc.storyboard!.instantiateViewController(withIdentifier: "InitialViewController")
                self.window!.rootViewController = vc
            }
        }
        return true
    }
@IBAction func buttonStart(_ sender: UIButton) {
        if (nameInput.text != "" && startKmInput.text != "") {

            let defaults = UserDefaults.standard
            defaults.set(false, forKey: "firstTime")

            performSegue(withIdentifier: "goToSecond", sender: self)
        }
    }

Solution

  • Well, you can just invert your logic and check whether the initial action happened or not, so you don't need to set a value at app launch. For instance:

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    
            if let rvc = self.window?.rootViewController {
    
                let defaults = UserDefaults.standard
    
                if !defaults.bool(forKey: "buttonStartPressed")  {
                    let vc = rvc.storyboard!.instantiateViewController(withIdentifier: "InitialViewController")
                    self.window!.rootViewController = vc
                }
            }
            return true
        }
    

    Then:

    @IBAction func buttonStart(_ sender: UIButton) {
            if (nameInput.text != "" && startKmInput.text != "") {
    
                let defaults = UserDefaults.standard
                defaults.set(true, forKey: "buttonStartPressed")
    
                performSegue(withIdentifier: "goToSecond", sender: self)
            }
    }