My intention is to add a tutorial to my app, which is supposed to show only once per user.

So far my approach has been to create a func which is being called when viewDidLoad:

func checkInitialVc() {
        firstTime = defaults.bool(forKey: "firstTime")

        if firstTime {
            let initialData = self.storyboard?.instantiateViewController(withIdentifier: "ViewController") as! ViewController
            self.show(initialData, sender: initialData)
        }
    }

The problem is that as I open the App, even tho it's the first time, nothing happens.



firstTime is declared global:

var firstTime: Bool = false


In the ViewController which is to be opened, but doesn't, I've got:

@IBAction func buttonStart(_ sender: UIButton) {
        firstTime = false
        defaults.set(firstTime, forKey: "firstTime")
        performSegue(withIdentifier: "goToSecond", sender: self)

    }

3 Answers

0
Community On

When you start the application it loads every swift file including your boolean. So in this case the steps it takes are:

var firstTime: Bool = False  // Everytime you startup -> false
class YourViewController: UIViewController {
  override func viewDidload(){
    checkInitialVc()
  }

  func checkInitialVc() {
    firstTime = defaults.bool(forKey: "firstTime")
    if firstTime { // is False so never enters brackets
      let initialData =  self.storyboard?.instantiateViewController(withIdentifier: "ViewController") as! ViewController
       self.show(initialData, sender: initialData)
    }
  }
}

So just try setting the global Bool as a UserDefault so that when you load the app it already has the value that will be set with your button after the view has loaded and the button has been pressed:

var firstTime = UserDefaults.standard.bool(forKey: "firstTime")
class YourViewController: UIViewController {
  override func viewDidload(){
    checkInitialVc() //calls your function when view is available
  }

  func checkInitialVc() {
    if !UserDefaults.standard.bool(forKey:"firstTime"){ // UserDefaults.standard.bool is by default false

    let initialData = self.storyboard?.instantiateViewController(withIdentifier: "ViewController") as! ViewController

    self.show(initialData, sender: initialData)
  }

  @IBAction func buttonStart(_ sender: UIButton) {
    UserDefaults.standard.set(true, forKey: "firstTime")
    /* 
    or     
    */
    performSegue(withIdentifier: "goToSecond", sender: self)
  }
}
0
matt On

The use of a global is wrong. Change

func checkInitialVc() {
    firstTime = defaults.bool(forKey: "firstTime")
    if firstTime {
        let initialData = self.storyboard?.instantiateViewController(withIdentifier: "ViewController") as! ViewController
        self.show(initialData, sender: initialData)
    }
}

To:

func checkInitialVc() {
    UserDefaults.standard.register(defaults:["firstTime":true]) // <--
    firstTime = UserDefaults.standard.bool(forKey: "firstTime")
    if firstTime {
        UserDefaults.standard.set(false, forKey: "firstTime") // <--
        let initialData = self.storyboard?.instantiateViewController(withIdentifier: "ViewController") as! ViewController
        self.show(initialData, sender: initialData)
    }
}
1
Madiyar On

Another way is changing semantics of the bool retrieved from user defaults, for example from firstTime to tutorialShown since if the key doesn't exist user defaults will return false.

func checkInitialVc() {
        tutorialShown = defaults.bool(forKey: "tutorialShown")

        if !tutorialShown {
            let initialData = self.storyboard?.instantiateViewController(withIdentifier: "ViewController") as! ViewController
            self.show(initialData, sender: initialData)
        }
}