Home > front end >  Swift Swiftui - Saving Color to UserDefaults and use it from @AppStorage
Swift Swiftui - Saving Color to UserDefaults and use it from @AppStorage

Time:08-01

In my App for MacOS and iOS I use colors created from here: https://uiwjs.github.io/ui-color/ and then f.e. Works fine.

Color(red: 1.47, green: 1.9, blue: 2.3).opacity(1)

However for some colors I want them saved in the userDefaults and read/write by UserDefaults.standard methodes and read/write by @AppStorage.

I did try to use, but this gives me runtime errors.

static let infoListRowReadBGColor = Color(red: 2.55, green: 1.71, blue: 1.07).opacity(1)
static let infoListRowUnReadBGColor = Color(red: 2.55, green: 2.12, blue: 1.38).opacity(1)

var defaults = UserDefaults.standard

defaults.setValue(InAppDefaults.infoListRowReadBGColor, forKey: "infoListRowReadBGColor")
defaults.setValue(InAppDefaults.infoListRowUnReadBGColor, forKey: "infoListRowUnReadBGColor")
        

What do I need to change to get this working, read and write, using UserDefaults.default and @AppStore? I did try the extension methode from a posting around here, but I guess I do something very wrong, because it doesn't work with @AppStorage.

Using XCode 13 and 14 for dev result for MacOS 12 and iOS 15.

CodePudding user response:

you can try converting color into data and store the data instead.

here's a uikit version extending UIColor you can use it for SwiftUI's Color too

import UIKit

extension UIColor {
    class func color(data: Data) -> UIColor {
        try! NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data) as! UIColor
    }

    func encode() -> Data {
        try! NSKeyedArchiver.archivedData(withRootObject: self, requiringSecureCoding: false)
    }
}

you can persist the color using the encode function and once you retrieve the data, you can pass it on the class func to get the color

CodePudding user response:

You can't by default store Color() in UserDefaults, but you can use @AppStorage and NSKeyedArchiver to achieve this result. The full example and documentation is provided from this article.

Create an extension:

import Foundation
import SwiftUI
import UIKit

extension Color: RawRepresentable {

    public init?(rawValue: String) {
        
        guard let data = Data(base64Encoded: rawValue) else{
            self = .black
            return
        }
        
        do{
            let color = try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data) as? UIColor ?? .black
            self = Color(color)
        }catch{
            self = .black
        }
        
    }

    public var rawValue: String {
        
        do{
            let data = try NSKeyedArchiver.archivedData(withRootObject: UIColor(self), requiringSecureCoding: false) as Data
            return data.base64EncodedString()
            
        }catch{
            
            return ""
            
        }
        
    }

}

And use it as such:

@AppStorage("colorkey") var storedColor: Color = .black
    
    var body: some View {
        
        VStack{
            ColorPicker("Persisted Color Picker", selection: $storedColor, supportsOpacity: true)
            }
}
  • Related