1

I am saving the storyboard name and the current viewController so that when a user hits "resume" on the home screen (resumeButtonWasPressed in HomeScreenVC), they can immediately be taken back to the view that they were previously looking at. Every time I print the values after setting them in my classes, the correct value gets printed out, such as "Chapter1" "Page2". However, only a percentage of the time does the user get taken to the correct view when they press "resume" on the home screen. The correct values to be saved are printed out in the classes themselves, but when I retrieve the values from UserDefaults in the HomeScreenVC, sometimes the wrong storyboard and viewController get printed out. My code is below.

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    _ = UserDefaults.standard
    _ = ["strength" : 0]
    _ = ["intellect" : 0]
    _ = ["charisma" : 0]
    _ = ["name" : ""]
    _ = ["storyBoard" : "Main"]
    _ = ["viewController" : "HomeScreenVC"]

    // Override point for customization after application launch.
    return true
}

The following is my code for HomeScreenVC with the non-essentials removed:

class HomeScreenVC: UIViewController {
    let defaults = UserDefaults.standard

    @IBAction func resumeButtonWasPressed(_ sender: Any) {
        let sb = defaults.string(forKey: "storyBoard")
        let vc = defaults.string(forKey: "viewController")
        let storyBoard : UIStoryboard = UIStoryboard(name: sb!, bundle: nil)
        let newViewController = storyBoard.instantiateViewController(withIdentifier: vc!)
        self.navigationController?.pushViewController(newViewController, animated: true)
    }

    override func viewDidAppear(_ animated: Bool) {
        let sb = defaults.string(forKey: "storyBoard")
        let vc = defaults.string(forKey: "viewController")
        print(sb!)
        print(vc!)
    }
}

This is my infoScreen VC with the non-essentials removed:

class InfoScreenVC: UIViewController {
    let defaults = UserDefaults.standard

    override func viewDidAppear(_ animated: Bool) {
        let storyboard = self.storyboard?.value(forKey: "name")
        UserDefaults.standard.set(storyboard, forKey: "storyBoard") // save to user defaults
        let newViewController = self.restorationIdentifier
        UserDefaults.standard.set(newViewController, forKey: "viewController")
    }
}

This is my page1VC with the non-essentials removed:

class Page1VC: UIViewController {
    let defaults = UserDefaults.standard

    override func viewDidAppear(_ animated: Bool) {
        let storyboard = self.storyboard?.value(forKey: "name")
        UserDefaults.standard.set(storyboard, forKey: "storyBoard") // save to user defaults                
        let newViewController = self.restorationIdentifier
        UserDefaults.standard.set(newViewController, forKey: "viewController")
    }
}

This is my Page2VC with the non-essentials removed:

class Page2VC: UIViewController {
    let defaults = UserDefaults.standard

    override func viewDidAppear(_ animated: Bool) {
        let storyboard = self.storyboard?.value(forKey: "name")
        UserDefaults.standard.set(storyboard, forKey: "storyBoard") // save to user defaults
        let newViewController = self.restorationIdentifier
        UserDefaults.standard.set(newViewController, forKey: "viewController")
    }
}
rmaddy
  • 314,917
  • 42
  • 532
  • 579
DomDicoco
  • 19
  • 3
  • 1. That code in `didFinishLaunchingWithOptions` doesn't actually do anything. 2. Post minimal code to demonstrate the issue. – rmaddy Aug 18 '18 at 01:02
  • I removed the functions that weren't relevant to the issue. Why doesn't the code in didFinishLaunchingWithOptions do anything? – DomDicoco Aug 18 '18 at 01:09
  • An underscore is a sign to the compiler that it can throw away the values that you pass to it. So you are doing nothing with it. – Josef Zoller Aug 18 '18 at 01:19
  • @JosefZoller ah ok. I just wanted to silence the xcode warnings. Thanks for that. I still am getting the wrong storyboard and vc when the app relaunches though. Any idea why this is happening? – DomDicoco Aug 18 '18 at 01:25

2 Answers2

0

Try to replace the code inside of applicationDidFinishLaunchingWithOptions with this:

let defaults = UserDefaults.standard
defaults.set(0, forKey: "strength")
defaults.set(0, forKey: "intellect")
defaults.set(0, forKey: "charisma")
defaults.set("", forKey: "name")
defaults.set("Main", forKey: "storyBoard")
defaults.set("HomeScreenVC", forKey: "viewController")

// Override point for customization after application launch.
return true

EDIT

Also you should check in applicationDidFinishLaunchingWithOptions, if the UserDefaults keys are already set and only set them there if they aren't set at this moment. E.g.:

let defaults = UserDefaults.standard
if defaults.object(forKey: "storyBoard") == nil { // you could use any other key that you use in the app
    defaults.set(0, forKey: "strength")
    defaults.set(0, forKey: "intellect")
    defaults.set(0, forKey: "charisma")
    defaults.set("", forKey: "name")
    defaults.set("Main", forKey: "storyBoard")
    defaults.set("HomeScreenVC", forKey: "viewController")
}

Otherwise they are overwritten at every app launch.

Josef Zoller
  • 921
  • 2
  • 8
  • 24
  • For some reason the program is getting "stuck" on one particular vc and not updating. It had been stuck on InfoScreenVC even though I visited every other page. After, I hit start and went through all of the pages one by one and when I relaunched the app, the storyboard was "InfoStoryboard" and the VC was "Page1VC". Page1VC is not inside of InfoStoryboard, so there was a mismatch of storyboard to a vc that was inside of a different storyboard. This almost seems like a threading/blocking issue... – DomDicoco Aug 18 '18 at 01:40
  • I can also provide a link to the repo if that would be helpful – DomDicoco Aug 18 '18 at 01:47
  • The code you propose in `applicationDidFinishLaunchingWithOptions` is not at all what you want. This would reset the defaults every time the app is restarted. If anything, those values should be used to register default values but you should not be setting them. – rmaddy Aug 18 '18 at 01:57
  • @rmaddy Can you suggest a better way to save the current storyboard and vc so that when the app is relaunched they can easily be retrieved? – DomDicoco Aug 18 '18 at 02:02
0

You are missing a synchronize() after you set all your valida in the user defaults. Just add this after setting the new values:

UserDefaults.standard.synchronize() 
Mihai Fratu
  • 7,579
  • 2
  • 37
  • 63
  • Please read the documentation for `synchronize`. It's obsolete and should not be used. – rmaddy Aug 18 '18 at 01:57
  • The method is not marked as deprecated. So calling it still forces a disk write of the in memory cache of the users default database... at least that’s my understanding – Mihai Fratu Aug 18 '18 at 02:01
  • See https://stackoverflow.com/questions/40808072/when-and-why-should-you-use-nsuserdefaultss-synchronize-method/40809748?s=1|45.7457#40809748 – rmaddy Aug 18 '18 at 02:06
  • Well yeah. As I said it’s not impossible to be in a situation when they are not automatically synced so I still think the OP should try my advice. If it does solve his issues my answer might be improved by telling him to only do it when the app goes to the background. But not sure it deserves a down vote :P – Mihai Fratu Aug 18 '18 at 02:13
  • @MihaiFratu Don't worry I appreciated your answer. – DomDicoco Aug 18 '18 at 02:15
  • @rmaddy I am synchronizing every time the app enters the background, but still I am sometimes not retrieving the correct storyboard and vc. Could this be how I'm terminating it in xcode? I am following your advice in your other post by first going back to the home screen on the simulator, then hitting the stop button and then re-running the app. – DomDicoco Aug 18 '18 at 02:17
  • 1
    @rmaddy I notice that if I give xcode a few seconds before I shut everything down and reboot the app, it seems to be okay. – DomDicoco Aug 18 '18 at 02:20