How do I decode an object array and retrieve it from userdefaults?

319 views Asked by At

I have an array with type [NotificationTriggers] that I would like to store in userdefaults. To do that, the data needs to be encoded and decoded. I have followed tutorials here:

https://cocoacasts.com/ud-5-how-to-store-a-custom-object-in-user-defaults-in-swift

and here:

https://www.hackingwithswift.com/example-code/system/how-to-load-and-save-a-struct-in-userdefaults-using-codable

But I still get an error that I can't seem to solve.

I have an extension of userDefaults where I do the magic in the get and set of the variable. NotificationTriggers Struct looks like this:

struct NotificationTriggers: Equatable, Codable {
    var doorName: String
    var notificationTrigger: String
}

Encoding seems to work, but in decoding I get an error saying

Cannot convert value of type '[Any]' to expected argument type 'Data'

This is the code:

extension UserDefaults {
    var notificationTrigger: [NotificationTriggers] {
        get {
            if let data = self.array(forKey: UserDefaultsKey.notificationTrigger.rawValue) {
                do {
                    let decoder = JSONDecoder()
                    //CODE BELOW PRODUCE ERROR
                    if let decodedData = try decoder.decode([NotificationTriggers]?.self, from: data) {
                            return decodedData
                    }
                } catch { }
            }
            return []

        }
        set {
            do {
                let encoder = JSONEncoder()
                let data = try encoder.encode(newValue)
                    
                self.setValue(data, forKey: UserDefaultsKey.notificationTrigger.rawValue)
                
            } catch { }
        }
    }
}

I have tried casting the data:

UserDefaultsKey.notificationTrigger.rawValue) as? Data // get warning "Cast from '[Any]?' to unrelated type 'Data' always fails"

UserDefaultsKey.notificationTrigger.rawValue) as? [NotificationTriggers] // get error "Cannot convert value of type '[NotificationTriggers]' to expected argument type 'Data'"

Not sure what's missing here. Any ideas?

1

There are 1 answers

1
Larme On

You save Data for the key UserDefaultsKey.notificationTrigger.rawValue with:

let encoder = JSONEncoder()
let data = try encoder.encode(newValue)
self.setValue(data, forKey: UserDefaultsKey.notificationTrigger.rawValue)

So the first mistake I see:

if let data = self.array(forKey: UserDefaultsKey.notificationTrigger.rawValue) {

array(forKey:)? No, data(forKey:), you didn't save an Array, you saved a Data, a Data that might after some decoding "hides" an Array, but the system doesn't know it. So, it should be:

if let data = self.data(forKey: UserDefaultsKey.notificationTrigger.rawValue) {

Then:

let decodedData = try decoder.decode([NotificationTriggers]?.self, from: data)

=>

let decodedData = try decoder.decode([NotificationTriggers].self, from: data)

Also, it's bad habit to have catch { }, if there is an error, you might want to know it:

catch {
    print("Error while doingSomethingToCustomizeHere: \(error)")
}