Save Label Text and Button States

Hello,


I'm for some help with using User Defaults to store text saved in my progressLabel and button states. The way this works is that each time the user taps a button, the button toggles "on" and "off" and if "on" a percentage is calculated and displayed in the progressLable as "___ % Complete!". I'd like to save this information so that the user can continually go back in and tap additional buttons as they progress, eventually reaching "100% Complete!".


Here is my code:

class ViewController: UIViewController {

@IBOutlet weak var progressLabel: UILabel!


var countClickedButtons: Int = 0 {

didSet {

let percent = Int(100.0 * Double(countClickedButtons) / 14.0)

progressLabel.text = String(percent) + " % Complete!"

}

}

override func viewDidLoad() {

super.viewDidLoad()

}


/


@IBAction func buttonPressed (_ sender: PRToggleButton) {

if !sender.isSelected {

countClickedButtons += 1

}else{

countClickedButtons -= 1

}

sender.isSelected = !sender.isSelected

}


@IBAction func saveButtonStates(_ sender: Any) {

UserDefaults.standard.set((sender as AnyObject).isSelected, forKey: "isSaved")

//I tried the above and several other ways of using UserDefaults from video tutorials, but so far all I get are crashes. With the above, nothing happens.

}


@IBAction func closeView(_ sender: Any) {

self.dismiss(animated: true, completion: nil)

}

}

Replies

As already commented by Claude31, it's a very strange result.

It implies `updateButtonPercentage()` is called before iOS establishes the connection to IBOutlets. You may be doing some odd things in somewhere you are not showing to us.

Anyway, the behavior you described cannot be reproduced with your code shown. You should better find where you are doing such odd things.

Here is the original version with the suggestions from OOPer

@IBOutlet weak var progressLabel: UILabel!
    @IBOutlet var toggleButtons: [PRToggleButton] = []
    func updateButtonPercentage() {
        let countSelected = toggleButtons.map{$0.isSelected ? 1 : 0}.reduce(0, +)
        if !toggleButtons.isEmpty {
            let percent = Int(100.0 * Double(countSelected) / Double(toggleButtons.count))
            progressLabel.text = "\(percent) % Complete"
        } else {
            progressLabel.text = "--- % Complete"
        }
    }
    func saveButtonState(_ button: PRToggleButton) {
        let buttonKey = "saved\(button.tag)"
        UserDefaults.standard.set(button.isSelected, forKey: buttonKey)
    }
    func loadButtonState(_ button: PRToggleButton) {
        let buttonKey = "saved\(button.tag)"
        button.isSelected = UserDefaults.standard.bool(forKey: buttonKey)
    }
    override func viewDidLoad() {
        super.viewDidLoad()
    }
    override func viewWillAppear(_ animated: Bool) {
        for button in toggleButtons {
            loadButtonState(button)
        }
        updateButtonPercentage()
    }
        /
    @IBAction func ButtonPressed (_ sender: PRToggleButton) {
        sender.isSelected = !sender.isSelected
        updateButtonPercentage()
        saveButtonState(sender)
    }
    @IBAction func closeView(_ sender: Any) {
        self.dismiss(animated: true, completion: nil)
    }
}

Below is what I changed from line 8 above as well as deleting the } else { statement in lines 9 and 10 above. This seems to work, but the button states are not saved when the view is closed and reopened. The percentage remains the same, but without the buttons remaining selected, the user can't tell from which buttons the percent was generated. I've also posted the code for the custom button that I'm using below.

unc updateButtonPercentage() {
        let countSelected = toggleButtons.map{$0.isSelected ? 1 : 0}.reduce(0, +)
        if !toggleButtons.isEmpty {
            let percent = Int(100.0 * Double(countSelected) / Double(toggleButtons.count))
            progressLabel.text = String(percent) + " % Complete"
        }
    }

Custom Button:

class PRToggleButton: UIButton {
    var isOn = false
    override init(frame: CGRect) {
        super.init(frame: frame)
        initButton()
    }
    required init?(coder aDecoder: NSCoder){
        super.init(coder: aDecoder)
        initButton()
    }
    func initButton(){
        layer.borderWidth = 2.0
        layer.borderColor = UIColor.blue.cgColor
        layer.cornerRadius = frame.size.height/3
        setTitleColor(UIColor.blue, for: .normal)
        addTarget(self, action: #selector(PRToggleButton.buttonPressed), for: .touchUpInside)
    }
    @objc func buttonPressed() {
        activateButton(bool: !isOn)
    }
    func activateButton(bool: Bool) {
        isOn = bool
        let color = bool ? UIColor.blue : .clear
        let titleColor = bool ? .white : UIColor.blue
        setTitleColor(titleColor, for: .normal)
        backgroundColor = color
    }
}

Hey Claude, how can I retrieve the state of my selected buttons if I'm saving buttons like this:

UserDefaults.standard.set([sender.title : String(sender.isSelected)], forKey: "isSaved")


I want to achive this result.

Thanks in advance!

That's an incredibly ofld thread.


You'd better create a new thread (may be with a reference to this one) and explain in detail what you want to achieve and the problem you face.

Awaiting for Moderator to approve my Post.

Here is the thread.
https://forums.developer.apple.com/thread/132583