Search code examples
swiftnsuserdefaultsswifty-jsonuserdefaults

Set array of objects in UserDefaults


how to set and later get array of json objects in UserDefaults?

My application crashes when i try to set it as follow:

import SwiftyJSON
var finalArray = [JSON]()

UserDefaults.standard.set(finalArray, forKey: "attemptedArray")

my data looks like:

[{
  "marked" : 3,
  "attempted" : true,
  "correct" : 3,
  "subject" : 1,
  "status" : true,
  "question" : 219,
  "answer" : 32931,
  "time" : 15,
  "score" : 5,
  "chapter" : 26
}, {
  "marked" : 4,
  "attempted" : true,
  "correct" : 4,
  "subject" : 1,
  "status" : true,
  "question" : 550,
  "answer" : 34256,
  "time" : 23,
  "score" : 10,
  "chapter" : 26
}, {
  "marked" : 1,
  "attempted" : true,
  "correct" : 1,
  "subject" : 1,
  "status" : true,
  "question" : 566,
  "answer" : 34317,
  "time" : 33,
  "score" : 14,
  "chapter" : 26
}]

Solution

  • UserDefaults can't save SwiftyJSON's JSON type. You have to save some type which they supports, in this case, you're looking for Data.

    Anyway, for saving Data to UserDefaults aren’t the best and you should save your Data to file somewhere else. To achieve this, you can use FileManager.


    So, create custom model for your data instead of using JSON and adopt Codable to your custom model

    struct Model: Codable {
        var marked, correct, subject, question, answer, time, score, chapter: Int
        var attempted, status: Bool
    }
    

    Then you should use this Model as type of element inside your array (note that then you’ll need to decode your response from Data using JSONDecoder (see below))

    var finalArray = [Model]()
    

    then you can use JSONEncoder for encoding your array of models to Data which you can write to some file

    do {
        let encoded = try JSONEncoder().encode(finalArray)
        let preferencesDirectoryURL = FileManager.default.urls(for: .libraryDirectory, in: .userDomainMask).first!.appendingPathComponent("Preferences", isDirectory: true)
        let fileURL = preferencesDirectoryURL.appendingPathComponent("fileName.json")
        try encoded.write(to: fileURL)
    } catch { print(error) }
    

    and JSONDecoder for decoding Data from saved file

    do {
        let preferencesDirectoryURL = FileManager.default.urls(for: .libraryDirectory, in: .userDomainMask).first!.appendingPathComponent("Preferences", isDirectory: true)
        let fileURL = preferencesDirectoryURL.appendingPathComponent("fileName.json")
    
        if let data = try? Data(contentsOf: fileURL) {
            let decoded = try JSONDecoder().decode([Model].self, from: data)
        }
    } catch { print(error) }