0

I'm trying to create an app which will have an option to customize button colors and have the colors set as a default until changed by the user.

I've researched using UserDefaults and keys, and I've tried to implement them into my code. Even though I don't get an error, the data resets when changing storyboards even though I've set the values to the key data.

Any help or advice would be appreciated since this is my first ever Xcode/Swift project. Also, if someone would be so kind as to explain how I would set button colors in other storyboards as well through the aforementioned options, I would really appreciate it.

//
//  SettingsViewController.swift
//  Calculator++
//
//  Created by School on 12/4/16.
//  Copyright © 2016 BlueFireStudios. All rights reserved.
//

import UIKit

class SettingsViewController: UIViewController {


//Setting default values
var defaults = UserDefaults.standard

//Setting slider starting positions

//Digit slider defaults
var redValue1: CGFloat = CGFloat(UserDefaults.standard.integer(forKey: "red"))
var greenValue1: CGFloat = CGFloat(UserDefaults.standard.integer(forKey:"green"))
var blueValue1: CGFloat = CGFloat(UserDefaults.standard.integer(forKey: "blue"))



//Outlet for display button labeled "4"
@IBOutlet weak var digitdisp: UIButton!

var myInt = Int()

//Displays digit color settings
func displayColors1() {
    digitdisp.backgroundColor = UIColor(red: redValue1, green: greenValue1, blue: blueValue1, alpha: 1.0)
    defaults.set(NSKeyedArchiver.archivedData(withRootObject: UIColor.red),
        forKey:"red")
     defaults.set(NSKeyedArchiver.archivedData(withRootObject: UIColor.blue), forKey:"blue")
      defaults.set(NSKeyedArchiver.archivedData(withRootObject: UIColor.green), forKey:"green")

}
//Setting R color in digit RGB set (red in func displayColors1)
@IBAction func redslider1(_ sender: UISlider) {
    redValue1 = CGFloat(sender.value)
    defaults.set(NSKeyedArchiver.archivedData(withRootObject: UIColor.red, forKey:"red")
    displayColors1()
}

//Setting G color in digit RGB set (green in func displayColors1)
@IBAction func greenslider1(_ sender: UISlider) {
    greenValue1 = CGFloat(sender.value)
     defaults.set(NSKeyedArchiver.archivedData(withRootObject: UIColor.green), forKey:"green")
    displayColors1()
}

//Setting B color in digit RGB set (blue in func displayColors1)
@IBAction func blueslider1(_ sender: UISlider) {
    blueValue1 = CGFloat(sender.value)
    defaults.set(NSKeyedArchiver.archivedData(withRootObject: UIColor.blue), forKey:"blue")


    displayColors1()

}



override func viewDidLoad() {
    super.viewDidLoad()
    myInt = 50
    displayColors1()


    // Do any additional setup after loading the view.
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}

/*
// MARK: - Navigation

// In a storyboard-based application, you will often want to do a little      preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    // Get the new view controller using segue.destinationViewController.
    // Pass the selected object to the new view controller.
}
*/

}

Z Amoss
  • 26
  • 2
  • 2
    It would be easier for people to diagnose, if you simplified your code down to the minimal code required to reproduce the problem. Ie, rewrite it to include only one set of colours, one button, one set of sliders. Test it, see if the problem still occurs, then post that code. – Son of a Beach Dec 06 '16 at 01:31
  • you can lower some of your codes complexity by saving a UIColor instead of 3 separate CGFloats. Why not just do: `defaults.set(signdisp.backgroundColor, forKey: "myFavoriteColor")`? – Joe Daniels Dec 06 '16 at 01:32
  • @Joe Daniels Can you really do that directly whith UIColor objects? The NSUserDefaults documentation suggests that it can only (directly) store property list data types (see https://developer.apple.com/reference/foundation/userdefaults ). For common work arounds for other data types, but in particular, UIColor, see http://stackoverflow.com/questions/1275662/saving-uicolor-to-and-loading-from-nsuserdefaults – Son of a Beach Dec 06 '16 at 01:43
  • I'm sorry, I've lost my mind! no of course not, haha, you just archive it! ex: `UserDefaults.standard.set(NSKeyedArchiver.archivedData(withRootObject: signdisp.backgroundColor), forKey: "myFavoriteColor")` and to unarchive: `signdisp.backgroundColor = NSKeyedUnarchiver.unarchiveObject(with:UserDefaults.standard.getObject(forKey: "myFavoriteColor"))` – Joe Daniels Dec 06 '16 at 01:50
  • @Joe Daniels I tried to use the method you said to archive the data, that works fine, but when I tried to put in the above unarchive code it throws the error "Type 'UserDefaults has no member 'standard' ". I also did shorten the code like Son of a Beach suggested, it should show above. Should I put the unarchiver in the scope instead? I had it placed there, but it kept throwing the 'Expected Declaration Error'. – Z Amoss Dec 06 '16 at 22:13
  • Also, the earlier defaults.set code you gave throws an error when moving the slider around. – Z Amoss Dec 06 '16 at 22:36
  • Trying this one more time: `var defaults = UserDefaults.standard` `defaults.set(NSKeyedArchiver.archivedData(withRootObject: UIColor.blue), forKey:"blue")` Reading in: `if let data = defaults.data(forKey:"blue"), let val = NSKeyedUnarchiver.unarchiveObject(with: data) as? UIColor{ print(val) }` I'd guess that the error is that the color is null because the slider values go out of range? – Joe Daniels Dec 07 '16 at 01:22
  • @Joe Daniels I tried what you said, and it seemed to work, but then I realized that for some reason the blue and red sliders both control the R value now! As well as the defaults still reset when I change storyboards. I've updated the code above to represent the program with your code put in to show you what I did. I would assume it has something to do with the setting of the CGFloat values at the top, but I'm not sure. Thanks for responding to my comment by the way, I appreciate it! – Z Amoss Dec 07 '16 at 22:34
  • Never mind, I fixed the blue being red issue! Turns out i had the variable for blue slider as the red one. Still trying to see if I can get your suggestion to work, I think I'm probably just using it in the wrong spot. – Z Amoss Dec 07 '16 at 22:41

2 Answers2

0

For one of your colour/button/slider sets, you are saving three values to defaults that you never read in and use anywhere:

defaults.set(CGFloat(redValue2), forKey: "SetRed2")
defaults.set(CGFloat(greenValue2), forKey: "SetGreen2")
defaults.set(CGFloat(blueValue2), forKey: "SetBlue2")

The only values that you do read from defaults are for your other completely unrelated set of keys:

var redValue1: CGFloat = CGFloat(UserDefaults.standard.integer(forKey: "SetRed1"))
var greenValue1: CGFloat = CGFloat(UserDefaults.standard.integer(forKey: "SetGreen1"))
var blueValue1: CGFloat = CGFloat(UserDefaults.standard.integer(forKey: "SetBlue1"))

Ie, you are reading (and writing) from defaults using keys ending in the character 1, but only writing (not reading) to defaults using keys ending in the character 2.

Son of a Beach
  • 1,733
  • 1
  • 11
  • 29
0

To save it:

var red: CGFloat = 0
var green: CGFloat = 0
var blue: CGFloat = 0
var alpha: CGFloat = 0

UserDefaults.standard.set([red, green, blue, alpha], forKey: "textColor")

To retrieve:

if let textColor = prefs.array(forKey: "textColor") {
        lblFirst.textColor = UIColor(red: textColor[0] as! CGFloat, green: textColor[1] as! CGFloat, blue: textColor[2] as! CGFloat, alpha: textColor[3] as! CGFloat)
    }
Emre AYDIN
  • 724
  • 8
  • 10