skip to Main Content

I’m completely new to programming. Trying to learn Swift. I’ve created the UI for my app. A simple data entry app for weight lifting PB’s. However when I close the app my data doesn’t update to new stored values. How do assign a variable string to each UITextfield entry, which when I close the app it will display its last stored value?

import UIKit

class ViewController: UIViewController, UITextFieldDelegate {
    @IBOutlet weak var benchPressPB: UITextField!
    @IBOutlet weak var squatPB: UITextField!
    @IBOutlet weak var deadliftPB: UITextField!
    @IBOutlet weak var ohpPB: UITextField!
    @IBOutlet weak var rackPullPB: UITextField!
    @IBOutlet weak var legPressPB: UITextField!
    @IBOutlet weak var pullUpsPB: UITextField!
    override func viewDidLoad() {
        super.viewDidLoad()
        self.benchPressPB.delegate = self
        self.squatPB.delegate = self
        self.deadliftPB.delegate = self
        self.ohpPB.delegate = self
        self.rackPullPB.delegate = self
        self.legPressPB.delegate = self
        self.pullUpsPB.delegate = self
    }
    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        textField.resignFirstResponder()
        return true
    }
}

P.S this may completely wrong and long already, but currently its achieving what I want it do, just not saving new inputted data. If there’s any shorter way to get the keyboard to hide on return, let me know!

2

Answers


  1. You can subclass UITextField and add a target for editing changed. Every time your text changes you can simply save its new value into user defaults. To make sure you use a unique key for each field you can override the accessibilityIdentifier and implement didSet to load the old values when you set its identifier:

    import UIKit
    
    class PersistentTextField: UITextField, UITextFieldDelegate {
        override var accessibilityIdentifier: String? {
            didSet {
                text = UserDefaults.standard.string(forKey: accessibilityIdentifier ?? "")
            }
        }
        override func didMoveToSuperview() {
            addTarget(self, action: #selector(editingChanged), for: .editingChanged)
            autocapitalizationType = .none
            autocorrectionType = .no
            delegate = self
        }
        @objc func editingChanged(_ textField: UITextField) {
            UserDefaults.standard.set(text ?? "", forKey: accessibilityIdentifier ?? "")
        }
        func textFieldShouldReturn(_ textField: UITextField) -> Bool {
            resignFirstResponder()
            return true
        }
    }
    

    Then in your view controller just make sure to set their id when your view loads:

    import UIKit
    
    class ViewController: UIViewController {
        
        @IBOutlet weak var benchPressPB: PersistentTextField!
        @IBOutlet weak var squatPB: PersistentTextField!
        @IBOutlet weak var deadliftPB: PersistentTextField!
        @IBOutlet weak var ohpPB: PersistentTextField!
        @IBOutlet weak var rackPullPB: PersistentTextField!
        @IBOutlet weak var legPressPB: PersistentTextField!
        @IBOutlet weak var pullUpsPB: PersistentTextField!
    
    
        override func viewDidLoad() {
            super.viewDidLoad()
            benchPressPB.accessibilityIdentifier = "bench press"
            squatPB.accessibilityIdentifier = "squat"
            deadliftPB.accessibilityIdentifier = "dead lift"
            ohpPB.accessibilityIdentifier = "ohp"
            rackPullPB.accessibilityIdentifier = "rack pull"
            legPressPB.accessibilityIdentifier = "leg press"
            pullUpsPB.accessibilityIdentifier = "pull ups"
        }
    }
    
    Login or Signup to reply.
  2. Your current code doesn’t do anything with the values a user enters into your text fields.

    You should

    • Set up a model object to hold the values that the user enters.

    • In your textFieldShouldReturn, collect the user input and save it
      into your model.

    • Decide on how you want to persist your app’s state so it restores
      when the app is launched. At it’s simplest, this could be saving each
      string to a different key/value pair in UserDefaults, or grouped
      together in a dictionary or an array.

    The code might look something like this: (not tested. Not even compiled. It will need cleanup before you can use it:

    @IBOutlet weak var benchPressPB: UITextField!
    @IBOutlet weak var squatPB: UITextField!
    @IBOutlet weak var deadliftPB: UITextField!
    @IBOutlet weak var ohpPB: UITextField!
    @IBOutlet weak var rackPullPB: UITextField!
    @IBOutlet weak var legPressPB: UITextField!
    @IBOutlet weak var pullUpsPB: UITextField!
    
    var textFields = [UITextField]
    var textFieldKeys = [
      "benchPressPB", 
      "squatPB", 
      "deadliftPB", 
      "ohpPB", 
      "rackPullPB", 
      "legPressPB", 
      "pullUpsPB"
    ]
    var textFieldStrings = [String]()
    
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // Note that you can hook up the delegates for your 
        // text fields in your Storyboard.
        self.benchPressPB.delegate = self
        self.squatPB.delegate = self
        self.deadliftPB.delegate = self
        self.ohpPB.delegate = self
        self.rackPullPB.delegate = self
        self.legPressPB.delegate = self
        self.pullUpsPB.delegate = self 
    
        textFields = [benchPressPB, squatPB, deadliftPB, ohpPB, rackPullPB, legPressPB, pullUpsPB] 
        // Read values from UserDefaults into the text fields.
        for (index, key) in textFieldKeys.enumerated() {
            let aValue = UserDefaults.standard.string(forKey: key)
            textFields[index].text = aValue
            textFieldStrings.append(aValue ?? "")
        }
            
    }
    
    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        textField.resignFirstResponder()
        let newText = textField.text
        if let index = textFields.firstIndex(of: textField) {
           textFieldStrings[index] = newText
           UserDefaults.standard.set(newText, forKey: textFieldKeys[index])
        }
        return true
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search