Search code examples
arraysswiftstringappenduserdefaults

Swift - User Defaults not loading array of strings when app is launched


So I have an app for a Midwestern car game where you count cows when you're driving and when you see a cemetery you lose half your cows. Whenever someone sees a cemetery, I have an emoji appear as an appended array of string, so they keep adding up. My problem is I can save the array to user defaults and it will print it correctly, but whenever I relaunch the app, the array goes back to a blank array of strings. So I know the data is saved correctly, just not loading when the app launches.

class ViewController: UIViewController {
    
    
    @IBOutlet weak var playerOneNameText: UITextField!
    @IBOutlet weak var numberOfCowsPlayerOne: UILabel!
    @IBOutlet weak var playerOneCows: UILabel!
    @IBOutlet weak var playerOneCemeteries: UILabel!
  
    
    let userDefaults = UserDefaults.standard
    
   
    var cemeteryEmoji: [String] = UserDefaults.standard.object(forKey: "CemeteryEmoji")! as? [String] ?? []

It will also strangely load the correct array in the field for display, but will start over any time a new cemetery is added:

override func viewDidLoad() {
        super.viewDidLoad()
        
        if userDefaults.value(forKey: "CemeteryEmoji") != nil{
            playerOneCemeteries.text = "\(UserDefaults.standard.object(forKey: "CemeteryEmoji")!)"
            print(cemeteryEmoji)
        }else {
            playerOneCemeteries.text = ""
        }
    
    }

And here's the function for all the cemetery data:

@IBAction func playerOneCemetery(_ sender: UIButton) {
        
        let cemeteryCows = UserDefaults.standard.integer(forKey: "TotalCows") / 2
        self.userDefaults.set(cemeteryCows, forKey: "TotalCows")
        print(cemeteryCows)
        self.numberOfCowsPlayerOne.text = "\(self.userDefaults.string(forKey: "TotalCows")!) cows"
        

        addCemeteryEmoji()
        
        print(UserDefaults.standard.object(forKey: "CemeteryEmoji")!)
        
        
        func addCemeteryEmoji() {
            
            cemeteryEmoji.append("🪦")
            print(cemeteryEmoji)
            self.playerOneCemeteries.text = "\(cemeteryEmoji.joined())"
            userDefaults.set(cemeteryEmoji.joined(), forKey: "CemeteryEmoji")
             
        }
    }

So I'm not sure if it's an issue simply when the app loads or if I need to save it a different way (although as I said, that works perfectly fine with all the print statements). Any help would be great.


Solution

  • The error occurs because you join the array right before saving it which creates a single string.

    And when you relaunch the app object(forKey: "CemeteryEmoji")! as? [String] fails.

    I highly recommend to name the array more meaningful and use the dedicated API array(forKey:).

    Name the array in plural form and declare an empty array

    var cemeteryEmojis = [String]()
    

    In viewDidLoad load the array from UserDefaults

    override func viewDidLoad() {
        super.viewDidLoad()
        
        if let emojis = userDefaults.array(forKey: "CemeteryEmoji") as? [String] {
            playerOneCemeteries.text = "\(emojis.joined())"
            cemeteryEmojis = emojis
            print(cemeteryEmojis)
        } else {
            playerOneCemeteries.text = ""
        }
    }
    

    And delete joined() in the set line of addCemeteryEmoji

    func addCemeteryEmoji() {       
        cemeteryEmojis.append("🪦")
        print(cemeteryEmojis)
        self.playerOneCemeteries.text = "\(cemeteryEmojis.joined())"
        userDefaults.set(cemeteryEmojis, forKey: "CemeteryEmoji") 
    }