简体   繁体   中英

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
}]

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) }
do{
            try let data = NSKeyedArchiver.archivedData(withRootObject: finalArray, requiringSecureCoding: false)
    UserDefaults.standard.set(data, forKey: "attemptedArray")
        }catch{
            print("Print exception here")
        }

Read:- Property List Programming Guide

Saving a lot of data in the NSuser defaults isn't recommended for some reasons:

  1. If you will delete some of the cells of the array you will need to delete them from the nsuser defaults. It will be easy only if you save them as an array and not as individuals.

  2. If you choose to save them as array every time you will delete or add one item you will need to save all of them. It can take slot of time if the array is big

  3. Anyone can access the NSuser defaults. So it isn't safe

Anyway I really recommend using core data. It saves you all the troubles I mentioned.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM