如何使用UserDefaults保存UIColor?

11

我正在尝试编写代码,以便如果用户按下“夜间模式”按钮,背景将变为黑色,并在用户关闭应用程序时保持黑色。(白天模式同样适用。)

请注意:我已经编写了按钮,当它们被按下时,所有场景都会改变到该模式。

以下是我的代码,我需要在两个if语句中都保存背景颜色:

if GlobalData.dayBool == true && GlobalData.night == false {
    backgroundColor = GlobalData.dayColor 
}

if GlobalData.nightBool == true && GlobalData.dayBool == false {
    backgroundColor = GlobalData.nightColor 
}

我的夜间和白天颜色:

struct GlobalData {
    static var score = 0
    static var dayColor = UIColor(red:0.93, green:0.93, blue:0.93, alpha:1.0)
    static var nightColor = UIColor(red:0.10, green:0.10, blue:0.10, alpha:1.0)  
    static var dayBool = true
    static var nightBool = true
}
2个回答

23

Swift 5.2或更高版本

请注意,这仅会将RGBA CGFloat值作为数据保存在属性列表中。这将使用32字节(原始数据),而使用NSKeyedUnarchiver(NSCoding)的标准方法需要424字节:

extension Numeric {
    var data: Data {
        var bytes = self
        return Data(bytes: &bytes, count: MemoryLayout<Self>.size)
    }
}

extension Data {
    func object<T>() -> T { withUnsafeBytes{$0.load(as: T.self)} }
    var color: UIColor { .init(data: self) }
}

extension UIColor {
    convenience init(data: Data) {
        let size = MemoryLayout<CGFloat>.size
        self.init(red:   data.subdata(in: size*0..<size*1).object(),
                  green: data.subdata(in: size*1..<size*2).object(),
                  blue:  data.subdata(in: size*2..<size*3).object(),
                  alpha: data.subdata(in: size*3..<size*4).object())
    }
    var rgba: (red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat)? {
        var (red, green, blue, alpha): (CGFloat, CGFloat, CGFloat, CGFloat) = (0, 0, 0, 0)
        return getRed(&red, green: &green, blue: &blue, alpha: &alpha) ?
        (red, green, blue, alpha) : nil
    }
    var data: Data? {
        guard let rgba = rgba else { return nil }
        return rgba.red.data + rgba.green.data + rgba.blue.data + rgba.alpha.data
    }
}

extension UserDefaults {
    func set(_ color: UIColor?, forKey defaultName: String) {
        guard let data = color?.data else {
            removeObject(forKey: defaultName)
            return
        }
        set(data, forKey: defaultName)
    }
    func color(forKey defaultName: String) -> UIColor? {
        data(forKey: defaultName)?.color
    }
}

extension UserDefaults {
    var backgroundColor: UIColor? {
        get { color(forKey: "backgroundColor") }
        set { set(newValue, forKey: "backgroundColor") }
    }
}

UserDefaults.standard.backgroundColor = .red
UserDefaults.standard.backgroundColor  // r 1.0 g 0.0 b 0.0 a 1.0

这对使用init(patternImage:)构建的颜色有效吗? - Cristik
它将简单地删除该值。 - Leo Dabus
@Cristik 注意,NSKeyedArchiver/NSKeyedUnarchiver 也会返回 nil。 - Leo Dabus
嗯...有趣,如果UIColor不是“常规”颜色,那么没有可靠的方法来存档它。 - Cristik
@Cristik 我不知道有没有这样的功能。最好的方法是保存图片,然后从中重新创建你需要的颜色。 - Leo Dabus

-4

最简单的方法是使用NSUserDefaults

简单示例 -

let defaults = NSUserDefaults.standardUserDefaults()
defaults.setObject("Coding Explorer", forKey: "userNameKey")

在这种情况下,您正在存储字符串"Coding Explorer",并且可以通过键"userNameKey"进行引用。我相信您可以看到如何将其融入您的解决方案中:P

一个很好的起点在这里

如果您想要更强大的东西,请查看CoreData,实现可能会更加复杂。CoreData可能不是您需要的简单状态持久性,但仍然值得一看。

链接在这里

编辑

这里有一个很好的示例,演示了如何将实际颜色保存到NSUserData中


1
我已经查看了那些网站。我试图保存背景颜色,但需要帮助来实现。我寻求帮助,但没有找到相关支持。 - Josh Schlabach

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接