9

I am using a tuple of arrays in one of my files and want to start saving it in UserDefaults. Here is how I am storing my current data:

typealias savemytuple = (Name: String, NameID: String, BookID: String, Picture: NSData)
var savefun = [savemytuple]()

I have researched and found I may need to do something with the following for saving:

NSKeyedArchiver.archivedDataWithRootObject

And this for retrieving:

NSKeyedUnarchiver.unarchiveObjectWithData

Not sure if this way will work as my tuple has multiple data types. Any idea on how to do this?

Pang
  • 9,564
  • 146
  • 81
  • 122
mbro12
  • 101
  • 2
  • 3
  • 1
    You should take a look at the Codable protocol (Swift 4 / Xcode 9.x). Don't use UserDefaults to persist your App data. Use a struct instead of a tuple and just write your resulting JSON data array to your application support folder. – Leo Dabus Feb 08 '18 at 03:37

2 Answers2

16

The values in UserDefaults must be property lists, so you need to convert each tuple to a property list. A Data is a property list, and there are several ways to convert things to Data.

One way is to stop using a tuple and use a struct instead. If all of the struct's stored properties conform to Codable, then you can ask Swift to generate everything needed to make the struct itself conform to Codable just by declaring the conformance. Both String and Data conform to Codable.

Once the struct is Codable, you can convert one of them, or even an array of them, into a property list via JSONEncoder or PropertyListEncoder:

import Foundation

struct Bookie: Codable {
    var name: String
    var nameId: String
    var bookId: String
    var picture: Data
}

let bookies = [
    Bookie(name: "mbro12", nameId: "id1", bookId: "b1", picture: Data()),
    Bookie(name: "mayoff", nameId: "id2", bookId: "b2", picture: Data())
]
let bookiesData = try! PropertyListEncoder().encode(bookies)
UserDefaults.standard.set(bookiesData, forKey: "bookies")

let fetchedData = UserDefaults.standard.data(forKey: "bookies")!
let fetchedBookies = try! PropertyListDecoder().decode([Bookie].self, from: fetchedData)
print(fetchedBookies)
rob mayoff
  • 375,296
  • 67
  • 796
  • 848
0

You have to convert the tuples into Dictionary to save it, not really a proper way, rather make your tuple into a custom object, then conform NSCoding protocol for a proper way to convert between data and object.

You don't really need NSKeyedArchiver.archivedDataWithRootObject, just simply convert the tuple into a Dictionary and have another function to convert back to the tuple type.

Tj3n
  • 9,837
  • 2
  • 24
  • 35