David Jacoby
David Jacoby

Reputation: 43

UserDefault not updating in main view controller

I am creating a simple counter application where the user can set a maximum number of patrons allowed in their place of business and when that number is reached they're given a notification that they're at maximum capacity. I'm using UserDefaults to store this data, however whenever I update the max number in the settings and return to the main view it's still using the previous max number. If I close the app and reopen it has the correct data. How do I make sure the data is being updated in the main view controller so it receives proper data?

Code

ViewController.swift (main view controller)

import UIKit
import AVFoundation

class ViewController: UIViewController {
    
    
    var counter = 0;
    var max = UserDefaults.standard.integer(forKey: "max");
    

    
    // Max patron alert function
    func showAlert() {
        let alertController = UIAlertController(title: "Limit Reached", message: "Your place of business has reached maximum capacity, please stop patrons from entering until capacity dissipates.", preferredStyle: .alert)
        alertController.addAction(UIAlertAction(title: "Dismiss", style: .default))
        
        self.present(alertController, animated: true, completion: nil)
        AudioServicesPlaySystemSound(kSystemSoundID_Vibrate)
    }

    @IBOutlet weak var count: UILabel!
    
    @IBAction func increment(_ sender: UIButton) {
        
        if counter < max {
            counter += 1;
            count?.text = String(counter);
        }
            
        
        if counter == max {
            showAlert();
        }
    }
    
    
    @IBAction func decrement(_ sender: UIButton) {
        if (counter == 0) {
            counter += 0;
        }
        else {
            counter -= 1;
        }
        count?.text = String(counter);

    }
    
    @IBAction func reset(_ sender: UIButton) {
        counter = 0;
        
        count?.text = String(counter);
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
//        UserDefaults.standard.synchronize()
        // Do any additional setup after loading the view.
    }
    

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

}

SettingsViewController.swift


import UIKit


class SettingsViewController: UIViewController {
    
    var mainViewController:ViewController?;

    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
    }
    
    @IBOutlet weak var maxOccupancy: UITextField!
    

    @IBAction func save(_ sender: UIButton) {
        let max = Int(maxOccupancy.text!);
        
        UserDefaults.standard.set(max, forKey: "max")
        UserDefaults.standard.synchronize()
        print(UserDefaults.standard.integer(forKey: "max"))
    }
    
    
    
    /*
    // MARK: - Navigation

    // In a storyboard-based application, you will often want to do a little preparation before navigation
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        // Get the new view controller using segue.destination.
        // Pass the selected object to the new view controller.
    }
    */

}

Upvotes: 0

Views: 1659

Answers (2)

Gereon
Gereon

Reputation: 17844

This line:

var max = UserDefaults.standard.integer(forKey: "max")

is executed only once, when ViewController is created. (BTW: no need for semicolons in Swift). Whatever happens to UserDefaults afterwards won't be reflected in its value.

Replace the line with

var max: Int {
    UserDefaults.standard.integer(forKey: "max")
}

so that every access to it actually goes out to fetch the value from UserDefaults.

These constructs are called "Computed Properties", explained here.

Upvotes: 3

Leo
Leo

Reputation: 3143

This happens because you read the counter number only once when ViewController is allocated. You might try to re-read it when ViewController will appear on the screen:

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

        max = UserDefaults.standard.integer(forKey: "max")
    }

Also, no need to use ; in every line's ending, Swift doesn't require it.

Upvotes: 1

Related Questions