4

I have an app and a walkthrough screen and I want to display the walkthrough screen if the user's open the app for first time, but I do it wrong. Should I put the code in the AppDelegate or in the ViewDidLoad inside my first screen. Here is the code I used:

  super.viewDidLoad()

    if UserDefaults.standard.bool(forKey: "isFirstLaunch") {

        UserDefaults.standard.set(true, forKey: "isFirstLaunch")
        UserDefaults.standard.synchronize()
    }
    let isFirstLaunch = UserDefaults.standard.value(forKey: "isFirstLaunch") as? Bool
    if isFirstLaunch! {

            let mainStoryboard = UIStoryboard(name: "ViewController", bundle: Bundle.main)
            let vc : ViewController = mainStoryboard.instantiateViewController(withIdentifier: "ViewController") as! ViewController
            self.present(vc, animated: true, completion: nil)


    }

and a picture of the error:

enter image description here

Any ides how to do it?

Cù Đức Hiếu
  • 5,569
  • 4
  • 27
  • 35
Ivan
  • 150
  • 1
  • 6
  • I have got a code on GitHub that does a similar job. Here's the link: https://github.com/karanthakakr04/Walkthrough-Demo.git I hope it serves your need. Also there's this reference tutorial if someone needs it: https://youtu.be/tNCsQe5vfRk – Karan Thakkar Feb 28 '17 at 12:02

4 Answers4

2

You have a number of problems:

  1. You unnecessarily set the key to true she it is already true
  2. You unnecessarily call synchronize
  3. You are using value(forKey:) instead of bool(forKey:)
  4. (And this is the cause of your crash) you don't unwrap the value you get, which means your app crashes when the value is nil

All you need is something like this:

let defaults = UserDefaults()
if !defaults.bool(forKey:"walkthroughShown") {
   defaults.set(true, forKey:"walkthroughShown")
   // Display your Walkthrough
}

viewDidLoad won't work as the location for this code and you would be better using this code in your app delegate to present the Walkthrough or your initial view controller

Paulw11
  • 108,386
  • 14
  • 159
  • 186
1

The (Apple) recommended way is to register the default value (as the class UserDefaults implies).

As soon as possible – for example in applicationWillFinishLaunching – insert

let defaultValues = ["isFirstLaunch" : true]
UserDefaults.standard.register(defaults: defaultValues)

The earliest moment is the init method in application delegate

override init()
{
    let defaultValues = ["isFirstLaunch" : true]
    UserDefaults.standard.register(defaults: defaultValues)
    super.init()
}

Then simply write

func viewDidLoad()
    super.viewDidLoad()
    let defaults = UserDefaults.standard
    if defaults.bool(forKey: "isFirstLaunch") {
        defaults.set(false, forKey: "isFirstLaunch")
        let mainStoryboard = UIStoryboard(name: "ViewController", bundle: Bundle.main)
        let vc : ViewController = mainStoryboard.instantiateViewController(withIdentifier: "ViewController") as! ViewController
        self.present(vc, animated: true, completion: nil)
    }
}

The default value is considered until it's changed the first time.

vadian
  • 274,689
  • 30
  • 353
  • 361
  • shall I write let defaultValues = ["isFirstLaunch" : true] UserDefaults.standard.register(defaults: defaultValues) in the app delegate and then the rest in the viewDidLoad or everything in one viewcontroller – Ivan Oct 28 '16 at 20:35
  • Yes, in AppDelegate, in any case you have to make sure that the lines to register the default value is executed **before** the `viewDidLoad` method in the view controller. – vadian Oct 28 '16 at 20:37
  • I gt an error signal SIGBART when I launch the app for its first time. I placed it in the applicationWillFinishLaunching But it is still now working Any ideas ? :( – Ivan Oct 28 '16 at 21:00
  • I updated the answer suggesting to put the code in the `init`method of AppDelegate. If the error still occurs it's not related to user defaults. – vadian Oct 28 '16 at 21:10
  • Again the same error. May I send you the code to have a look , since you are more professional – Ivan Oct 28 '16 at 21:21
0

Your error has to do with unwrapping an optional value. What you should do is check to see if there is a value in user defaults at all.

if let isFirstLaunch = UserDefaults.standard.bool(forKey: "isFirstLaunch") {
    //execute code for when it isn't the first launch
} else {
    //set value of isFirstLaunch for the first time
}

If isFirstLaunch is nil, that will mean it is the first launch.

Adam Zarn
  • 1,868
  • 1
  • 16
  • 42
0

You should unwrap the value first:

if let isFirstStart = UserDefaults.standard.value(forKey: "isFirstLaunch") as? Bool {
   // the isFirstStart value exists, you can check the value
} else {
   // the isFirstStart value does not exist
}

I think isFirstStart is a bad wording convention, because it can't be true in the first time (because it has not been set before). You should use for instance hasStarted, which indicates if the value does not exist, it has not been started before, if exists and true, it has been.

Hope this helps, feel free to ask.

Daniel
  • 357
  • 2
  • 11