如何将包含对象的数组保存到 UserDefaults

How to save an Array with Objects to UserDefaults

我的对象符合新的 Swift 4 Codeable 协议。如何在 UserDefaults?

中保存这些对象的数组
struct MyObject: Codeable {
    var name: String
    var something: [String]
}

myObjectsArray = [MyObject]() // filled with objects
UserDefaults.standard.set(myObjectsArray, forKey: "user_filters")

错误

Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Attempt to insert non-property list object

哇,我成功了:

这里是 Swift 4 保存 ArrayCodeable 对象的语法:

我的解决方案是将其编码为 JSON 对象并保存:

static var getAllObjects: [MyObject] {
      let defaultObject = MyObject(name: "My Object Name")
      if let objects = UserDefaults.standard.value(forKey: "user_objects") as? Data {
         let decoder = JSONDecoder()
         if let objectsDecoded = try? decoder.decode(Array.self, from: objects) as [MyObject] {
            return objectsDecoded
         } else {
            return [defaultObject]
         }
      } else {
         return [defaultObject]
      }
   }

 static func saveAllObjects(allObjects: [MyObject]) {
      let encoder = JSONEncoder()
      if let encoded = try? encoder.encode(allObjects){
         UserDefaults.standard.set(encoded, forKey: "user_objects")
      }
 }

您可以使用更通用的方法,使用具有特定类型的数组:

(myObject = 您喜欢的任何自定义可编码对象)

(myKey = 一个字符串常量键能够retrieve/set特定的数组)

//set
setObject(myArray, forKey: mykey)

//get
let myArray = getObject(forKey: mykey, castTo: Array<myObject>.self)

还有泛型函数,适用于任何类型:

func setObject<Object>(_ object: Object, forKey: String) where Object: Encodable
{
    let encoder = JSONEncoder()
    do {
        let data = try encoder.encode(object)
        set(data, forKey: forKey)
        synchronize()
    } catch let encodeErr {
        print("Failed to encode object:", encodeErr)
    }
}
    
func getObject<Object>(forKey: String, castTo type: Object.Type) -> Object? where Object: Decodable
{
    guard let data = data(forKey: forKey) else { return nil }
    let decoder = JSONDecoder()
    do {
        let object = try decoder.decode(type, from: data)
        return object
    } catch let decodeError{
        print("Failed to decode object:" , decodeError)
        return nil
    }
}