How to save list of object in user Default?

2019-01-26 00:16发布

问题:

my object is :

 struct Order: Codable {
        var item_id:String = ""
        var quantity:Int = 0
        var image:String = ""
        var name:String = ""
        var desc:String = ""
    }

and the class of function is :

    class func saveOrder(value: [Order]) {
        print(value)
        let placesData = NSKeyedArchiver.archivedData(withRootObject: value)
        UserDefaults.standard.set(placesData, forKey: "orderHistoryArray")
    }

    class func getOrder() -> [Order] {
        if let order = UserDefaults.standard.array(forKey: "orderHistoryArray") {
            return order as! [Order]
        }
        return []
    }

when i try to use this function :

            SavedData.saveOrder(value: itemsInCart)

it's not working with me , any help ?!!!

回答1:

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


回答2:

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


回答3:

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")
}


回答4:

Codable

You can save and load your array to/from UserDefaults using Codable.

Saving

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")
}

Loading

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
}


回答5:

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


回答6:

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