Search code examples
iosswiftnsuserdefaults

Store my custom Class in UserDefaults, and casting(parsing) this UserDefault to reach values (Swift 4.2)


I have created a dummy IOS Application to explain my questions well. Let me share it with all details:

  • There are 2 Pages in this dummy IOS Application: LoginPageViewController.swift and HomepageViewController.swift
  • Storyboard id values are: LoginPage, Homepage.
  • There is login button in Login page.
  • There are 3 labels in Homepage.
  • App starts with Login page.
  • And i have a class file: UserDetail.swift
  • And there is one segue from login page to home page. Segue id is: LoginPage2Homepage

UserDetail.swift file

import Foundation

class UserDetail {
    var accountIsDeleted = false
    var userGUID : String?
    var userAge: Int?
}

LoginPageViewController.swift file

import UIKit
class LoginPageViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
    }

    @IBAction func loginButtonPressed(_ sender: UIButton) {
        var oUserDetail = UserDetail()
        oUserDetail.accountIsDeleted = true
        oUserDetail.userAge = 38
        oUserDetail.userName = "Dirk Kuyt"

        UserDefaults.standard.set(oUserDetail, forKey: "UserCredentialUserDefaults")
        UserDefaults.standard.synchronize()

        performSegue(withIdentifier: "LoginPage2Homepage", sender: nil)
    }
}

HomepageViewController.swift file

import UIKit

class HomepageViewController: UIViewController {

    var result_userGUID = ""
    var result_userAge = 0
    var result_isDeleted = false


    @IBOutlet weak var labelUserGuidOutlet: UILabel!
    @IBOutlet weak var labelAgeOutlet: UILabel!
    @IBOutlet weak var labelAccountIsDeletedOutlet: UILabel!

    override func viewDidLoad() {
        super.viewDidLoad()

        self.setVariablesFromUserDefault()

        labelUserGuidOutlet.text = result_userGUID
        labelAgeOutlet.text = String(result_userAge)
        labelAccountIsDeletedOutlet.text = String(result_isDeleted)
    }

    func setVariablesFromUserDefault()
    {
        if UserDefaults.standard.object(forKey: "UserCredentialUserDefaults") != nil
        {
            // I need a help in this scope
            // I have checked already: My UserDefault exists or not.
            // I need to check type of the value in UserDefault if UserDefault is exists. I need to show print if type of the value in UserDefault is not belongs to my custom class.

            // And then i need to cast UserDefault to reach my custom class's properties: userGUID, userAge, isDeleted
        }
        else
        {
            print("there is no userDefault which is named UserCredentialUserDefaults")
        }
    }
}

My purposes:

  1. I would like to store my custom class sample(oUserDetail) in UserDefaults in LoginPageViewController with login button click action.
  2. I would like to check below in home page as a first task: My UserDefault exists or not ( I did it already)
  3. I would like to check this in home page as a second task: if my UserDefault exists. And then check type of the UserDefault value. Is it created with my custom class? If it is not. print("value of userdefault is not created with your class")
  4. Third task: If UserDefault is created with my custom class. And then parse that value. Set these 3 variables: result_userGUID, result_userAge, result_isDeleted to show them in labels.

I get an error after I click the login button in Login Page. Can't I store my custom class in UserDefaults? I need to be able to store because I see this detail while I am writing it:

UserDefaults.standart.set(value: Any?, forKey: String)

My custom class is in Any scope above. Isn't it?


Solution

  • You can't store a class instance without conforming to NSCoding / Codable protocols

    class UserDetail : Codable  {
       var accountIsDeleted:Bool? // you can remove this as it's useless if the you read a nil content from user defaults that means no current account
       var userGUID : String?
       var userAge: Int?
    }
    

    store

    do { 
      let res = try JSONEncoder().encode(yourClassInstance)
      UserDefaults.standard.set(value:res,forKey: "somekey")
    }
    catch { print(error) }
    

    retrieve

    do {
       if let data =  UserDefaults.standard.data(forKey:"somekey") {
          let res = try JSONDecoder().decode(UserDetail.self,from:data)
       } else {
         print("No account")
       }
    }
    catch { print(error) }