-1

This is a similar approach to Save dictionary to UserDefaults, however, it is intended for SwiftUI, not using a single line like set, so I want to store the value somewhere with a variable so I can call it easily. Also it's different because I'm asking for an initialization.

I have the following:

@Published var mealAndStatus: Dictionary

init() {
    mealAndStatus = ["Breakfast": "initial", "Snack": "notSet", "Lunch": "notSet", "Snack2": "notSet", "Dinner": "notSet"]
    if let storedDay = UserDefaults.standard.value(forKey: "mealAndStatus") {
        mealAndStatus = storedDay as! Dictionary
    }
}

1- How do I correctly store that dictionary in UserDefaults in SwiftUI?

2- That init, do I have to call it at the beginning of ContentView? Or can I leave it on the other swift file like that? Not sure how the init gets called.

I already made one with bool working:

@Published var startDay: Bool

init() {
    startDay = true
    if let storedDay = UserDefaults.standard.value(forKey: "startDay") {
        startDay = storedDay as! Bool
    }
}

but the dictionary doesn't seem to work. I need to initialize that dictionary and also store it in UserDefaults so I can access it later. Any help is appreciated.

Arturo
  • 3,254
  • 2
  • 22
  • 61

2 Answers2

0

Using JSONEncoder and JSONDecoder would help you convert to data any struct or dictionary that conforms to codable.

let arrayKey = "arrayKey"

func store(dictionary: [String: String], key: String) {
    var data: Data?
    let encoder = JSONEncoder()
    do {
        data = try encoder.encode(dictionary)
    } catch {
        print("failed to get data")
    }
    UserDefaults.standard.set(data, forKey: key)
}

func fetchDictionay(key: String) -> [String: String]? {
    let decoder = JSONDecoder()
    do {
        
        if let storedData = UserDefaults.standard.data(forKey: key) {
            let newArray = try decoder.decode([String: String].self, from: storedData)
            print("new array: \(newArray)")
            return newArray
        }
    } catch {
        print("couldn't decode array: \(error)")
    }
    return nil
}

// You would put this where you want to save the dictionary
let mealAndStatus = ["Breakfast": "initial", "Snack": "notSet", "Lunch": "notSet", "Snack2": "notSet", "Dinner": "notSet"]

store(dictionary: mealAndStatus, key: arrayKey)


// You would put this where you want to access the dictionary

let savedDictionary = fetchDictionay(key: arrayKey)

On a side note, you probably shouldn't be using standard defaults for storing stuff like this. Storing it as a database, or saving it in a file especially with encryption on eith the database or the file might be a bit safer.

Leo
  • 1,508
  • 13
  • 27
HalR
  • 11,411
  • 5
  • 48
  • 80
  • I thank you for showing me the Encoder which I didn't know, and I'll definitely look into it, but all I'm trying to do right now is predefine a simple dictionary with some elements at app installation, and store it on the defaults. That's why the init – Arturo Apr 26 '20 at 03:30
0

This is the perfect solution I found for SwiftUI:

Store this somewhere, in my case I created a class just for UserDefaults:

@Published var mealAndStatus: [String: Date] =
    UserDefaults.standard.dictionary(forKey: "mealAndStatus") as? [String: Date] ?? [:] {
    didSet {
        UserDefaults.standard.set(self.mealAndStatus, forKey: "mealAndStatus")
    }
}

That above initializes the dictionary and also creates a variable to be easily called and use to update the value. This can be modified at lunch time and add new values, that way is initialized with whatever I want.

Furthermore, now on Apple Dev wwdc20 they announced a new way of handling UserDefaults with SwiftUI which may be even better than the above. The propery wrapper is called: @AppStorage.

Arturo
  • 3,254
  • 2
  • 22
  • 61