my object is :
struct Order: Codable {
var item_id:String = \"\"
var quantity:Int = 0
var image:String = \"\"
var name:Strin
I use this class to solve that :
class Order: NSObject, NSCoding {
var item_id:String = ""
var quantity:String = ""
var image:String = ""
var name:String = ""
var desc:String = ""
init(item_id: String ,quantity : String , image : String , name: String, desc: String){
self.item_id = item_id
self.quantity = quantity
self.image = image
self.name = name
self.desc = desc
}
func encode(with aCoder: NSCoder) {
aCoder.encode(item_id, forKey: "item_id")
aCoder.encode(quantity, forKey: "quantity")
aCoder.encode(image, forKey: "image")
aCoder.encode(name, forKey: "name")
aCoder.encode(desc, forKey: "desc")
}
required init?(coder aDecoder: NSCoder) {
self.item_id = aDecoder.decodeObject(forKey: "item_id") as! String
self.quantity = aDecoder.decodeObject(forKey: "quantity") as! String
self.image = aDecoder.decodeObject(forKey: "image") as! String
self.name = aDecoder.decodeObject(forKey: "name") as! String
self.desc = aDecoder.decodeObject(forKey: "desc") as! String
}
}
then i use this functions to use it
class func save(value : Order){
var orderArray:[Order] = retrive()
orderArray.append(value)
let orderArrayAchived = NSKeyedArchiver.archivedData(withRootObject: orderArray)
UserDefaults.standard.set(orderArrayAchived, forKey: "orderArray")
}
class func saveListOfOrder(value: [Order]) {
print(value)
let cartArrayAchived = NSKeyedArchiver.archivedData(withRootObject: value)
UserDefaults.standard.set(cartArrayAchived, forKey: "orderArray")
}
class func retrive()-> [Order]{
let orderData = UserDefaults.standard.object(forKey: "orderArray") as? NSData
if orderData == nil
{
return [Order]()
}
let orderArray = NSKeyedUnarchiver.unarchiveObject(with: orderData! as Data) as? [Order]
return orderArray!
}
You are mixing up the protocols Codable and NSCoding
1) NSCoding
NSKeyed(Un)Archiver belongs to NSCoding. To use it you have to declare Order as class inheriting from NSObject and to adopt the protocol and its required methods
class Order: NSObject, NSCoding {
var item_id : String // no need to assign default values
var quantity : Int
var image : String
var name : String
var desc : String
required init(coder decoder: NSCoder)
{
item_id = decoder.decodeObject(forKey: "item_id") as! String
quantity = decoder.decodeInteger(forKey: "quantity")
image = decoder.decodeObject(forKey: "image") as! String
name = decoder.decodeObject(forKey: "name") as! String
desc = decoder.decodeObject(forKey: "desc") as! String
}
func encode(with coder: NSCoder)
{
coder.encode(item_id, forKey: "item_id")
coder.encode(quantity, forKey: "quantity")
coder.encode(image, forKey: "image")
coder.encode(name, forKey: "name")
coder.encode(desc, forKey: "desc")
}
}
Then you can load and save the data
class func saveOrder(value: [Order]) {
print(value)
let placesData = NSKeyedArchiver.archivedData(withRootObject: value)
UserDefaults.standard.set(placesData, forKey: "orderHistoryArray")
}
class func getOrder() -> [Order] {
guard let orderData = UserDefaults.standard.data(forKey: "orderHistoryArray"),
let order = NSKeyedUnarchiver.unarchiveObject(with: orderData) as? [Order] else { return [] }
return order
}
2) Codable
With Codable you can keep your struct. Just adopt the protocol and save the Data created by the encoder to disk
struct Order : Codable {
var item_id : String
var quantity : Int
var image : String
var name : String
var desc : String
}
// Both methods `throw` to hand over an en-/decoding error to the caller
class func saveOrder(value: [Order]) throws {
print(value)
let placesData = try JSONEncoder().encode(value) else { return }
UserDefaults.standard.set(placesData, forKey: "orderHistoryArray")
}
class func getOrder() throws -> [Order] {
guard let orderData = UserDefaults.standard.data(forKey: "orderHistoryArray") else { return [] }
return try JSONDecoder().decode([Order].self, from: orderData)
}
For your NSKeyedArchiver.archivedData(withRootObject: value) to work, your Order needs to conform to the Codable protocol. Just add these in your Order struct to this and it should work just fine.
required public init(coder decoder: NSCoder) {
item_id = decoder.decodeObject(forKey: "item_id") as? String ?? ""
quantity = decoder.decodeObject(forKey: "quantity") as? Int ?? 0
image = decoder.decodeObject(forKey: "image") as? String ?? ""
name = decoder.decodeObject(forKey: "name") as? String ?? ""
desc = decoder.decodeObject(forKey: "desc") as? String ?? ""
}
public func encode(with coder: NSCoder) {
coder.encode(item_id, forKey: "item_id")
coder.encode(quantity, forKey: "quantity")
coder.encode(image, forKey: "image")
coder.encode(name, forKey: "name")
coder.encode(desc, forKey: "desc")
}
If you implement Codable then use
do {
let data = try JSONEncoder().encode(arr)
// save data here
// to load
let data = //// get it here
let arr = try JSONDecoder().decode([Order].self,data)
}
catch {
print(error)
}
You can save and load your array to/from UserDefaults using Codable.
This is how you save it
class func saveOrders(_ orders: [Order]) {
guard let data = try? JSONEncoder().encode(orders) else { return }
UserDefaults.standard.set(data, forKey: "orders")
}
And this is how you load it
class func loadOrders() -> [Order] {
guard
let data = UserDefaults.standard.data(forKey: "orders"),
let orders = try? JSONDecoder().decode([Order].self, from: data)
else { return [] }
return orders
}
You can just use Property list encoder and Property list decoder to save your model to User Defaults. Its easy:
Suppose you have a model of type Order,
class func saveOrder(value: [Order]) {
PropertyListEncoder().encode(value), forKey: "Somekey")
}
class func getOrder() -> [Order]? {
if let data = UserDefaults.standard.value(forKey: "Somekey") as? Data {
let orderDetail = try? PropertyListDecoder().decode([Order].self, from: data)
return orderDetail!
} else {
return nil
}
}
general example
Suppose you use Json Decoder to decode some data like so:
let decodedValue = try JSONDecoder().decode(Order.self, from: data)
OR
let decodedValue : Order = Order(a: 1, b: 0) // your order model value type,
// Now you can save the decoded model object to User defaults easily
do {
UserDefaults.standard.set(try PropertyListEncoder().encode(decodedValue), forKey: "Some key")
} catch let err {
print(err)
}