skip to Main Content

The array saved in UIPickerView as a dictionary type UserDefaults in EventViewController disappears when it returns to ViewController.
Save the character put in UITextField with @IBAction of Button.
I want to keep the saved string.
I don’t know the solution.
Xcode 12.2

class EventViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource, UITextFieldDelegate {
    
    @IBOutlet weak var partsPickerView: UIPickerView!
    @IBOutlet weak var partsLabel: UILabel!
    @IBOutlet weak var menuPickerView: UIPickerView!
    @IBOutlet weak var menuLabel: UILabel!
    @IBOutlet weak var menuTextField: UITextField!

Put a dictionary type array

    var menuDataList: [String: [String]] = [
        "Leg": ["Squat","Leg press","Leg extension"],
        "Back": ["Deadlift","Bent over row","Chinning"],
        "Chest": ["Barbell bench press","Dumbbell bench press","Incline Dumbbell Bench Press"]
    ]
    var partsDataList: [String] = [
        "Leg","Back","Chest"
    ]
    var selectedParts = ""

Delegate settings

override func viewDidLoad() {
        super.viewDidLoad()

        partsPickerView.delegate = self
        partsPickerView.dataSource = self
        menuPickerView.delegate = self
        menuPickerView.dataSource = self
        menuTextField.delegate = self
        
        partsPickerView.tag = 1
        menuPickerView.tag = 2
        selectedParts = partsDataList[0]
    }

Instantiate UserDefaults

    let userDefaults = UserDefaults.standard
    let keyMenuDataList = "newMenu"

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

Add event button

    @IBAction func didTapAddMenuButton(_ sender: Any) {
        if (menuTextField.text?.isEmpty ?? true == false) {
            
            let okAlert = UIAlertController(title: "保存されました。", message: "", preferredStyle: .alert)
            let closeAction = UIAlertAction(title: "閉じる", style: .default) { (action: UIAlertAction) in }
            okAlert.addAction(closeAction)
            present(okAlert, animated: true, completion: nil)
            
            if let text = menuTextField.text {
                
                menuDataList[selectedParts]?.append(text)
                
                menuDataList = userDefaults.dictionary(forKey: "keyMenuDataList") as? [String: [String]] ?? [:]
                
                userDefaults.set(menuDataList, forKey: "keyMenuDataList")
                
            }
            
        } else {
            
            let ngAlert = UIAlertController(title: "テキストが空です。", message: "", preferredStyle: .alert)
            let closeAction = UIAlertAction(title: "閉じる", style: .default) { (action: UIAlertAction) in }
            ngAlert.addAction(closeAction)
            present(ngAlert, animated: true, completion: nil)
            
        }
        menuPickerView.reloadAllComponents()
        
    }

UIPickerView settings

func numberOfComponents(in pickerView: UIPickerView) -> Int {
        return 1
    }
    
    func pickerView(_ pickerView: UIPickerView,
                    numberOfRowsInComponent component: Int) -> Int {
        if pickerView.tag == 1{
            return partsDataList.count
        } else if pickerView.tag == 2{
            return menuDataList[selectedParts]?.count ?? 0
        } else {
            return 0
        }
    }
    
    func pickerView(_ picker: UIPickerView,
                    titleForRow row: Int,
                    forComponent component: Int) -> String? {
        if picker.tag == 1 {
            return partsDataList[row]
        } else if picker.tag == 2 {
            return menuDataList[selectedParts]?[row] ?? ""
        } else {
            return ""
        }
    }
    
    func pickerView(_ pickerView: UIPickerView,
                    didSelectRow row: Int,
                    inComponent component: Int) {
        if pickerView.tag == 1 {
            partsLabel.text = partsDataList[row]
            selectedParts = partsDataList[row]
            menuPickerView.reloadAllComponents()
        } else if pickerView.tag == 2 {
            menuLabel.text = menuDataList[selectedParts]?[row] ?? ""
        } else {
            return
        }
    }

3

Answers


  1. Chosen as BEST ANSWER

    I moved this to viewDidLoad and solved it.

    menuDataList = userDefaults.dictionary(forKey: "keyMenuDataList") as? [String: [String]] ?? [:]
    
    override func viewDidLoad() {
            super.viewDidLoad()
    
            partsPickerView.delegate = self
            partsPickerView.dataSource = self
            menuPickerView.delegate = self
            menuPickerView.dataSource = self
            menuTextField.delegate = self
            
            partsPickerView.tag = 1
            menuPickerView.tag = 2
            selectedParts = partsDataList[0]
    
            menuDataList = userDefaults.dictionary(forKey: "keyMenuDataList") as? [String: [String]] ?? [:]
    
        }
    
        @IBAction func didTapAddMenuButton(_ sender: Any) {
            if (menuTextField.text?.isEmpty ?? true == false) {
                
                let okAlert = UIAlertController(title: "保存されました。", message: "", preferredStyle: .alert)
                let closeAction = UIAlertAction(title: "閉じる", style: .default) { (action: UIAlertAction) in }
                okAlert.addAction(closeAction)
                present(okAlert, animated: true, completion: nil)
                
                if let text = menuTextField.text {
                    
                    menuDataList[selectedParts]?.append(text)
                                    
                    userDefaults.set(menuDataList, forKey: "keyMenuDataList")
                    
                }
                
            } else {
                
                let ngAlert = UIAlertController(title: "テキストが空です。", message: "", preferredStyle: .alert)
                let closeAction = UIAlertAction(title: "閉じる", style: .default) { (action: UIAlertAction) in }
                ngAlert.addAction(closeAction)
                present(ngAlert, animated: true, completion: nil)
                
            }
            menuPickerView.reloadAllComponents()
            
        }
    

  2. Let’s see your code:

    menuDataList = userDefaults.dictionary(forKey: "keyMenuDataList") as? [String: [String]] ?? [:]
    userDefaults.set(menuDataList, forKey: "keyMenuDataList")
    

    You assigned the userDefaults to menuDataList. But when you first get value for key from userDefaults, it’s value is a nil. So your code is like:

    menuDataList = [:];
    userDefaults.set([:], forKey: "keyMenuDataList")
    

    Your see, the userDefaults will always be [:] and you clean the menuDataList again and again.
    This code: menuDataList = userDefaults.dictionary(forKey: "keyMenuDataList") as? [String: [String]] ?? [:] is useless, you can just remove it and try again.

    Login or Signup to reply.
  3. Did you register the UserDefaults keys?

    You need to call this function on every time you launch your app again.

    UserDefaults.standard.register(defaults: [String : Any])
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search