简体   繁体   中英

How to use UserDefaults.standard save custom Data?

My Data Class

import Foundation

class People {

let peopleImage : String
let peopleTime : Int
let peopleName : String

init(image:String, second:Int, name:String) {

    peopleImage = image
    peopleTime = second
    peopleName = name

}

My Data List File

import Foundation

class CustomPeopleList {

    var peopleList = [

        People(image: "Man", second: 12, name: "Andy"),
        People(image: "Woman", second: 60, name: "Kevin"),



    ]

}

my viewController :

let defaults = UserDefaults.standard    
var allPeopleList = CustomPeopleList

There is a button, when I click button it will delete the first item in the Data List, but I find it always error. my userdefault code is this:

self.allPeopleList.remove(at: indexPathTimer.row)
let aaa = self.allPeopleList
let newPeopleData = NSKeyedArchiver.archivedData(withRootObject: self.allPeopleList)
self.defaults.set(aaa, forKey: "myPeopleData")

and when i want to use it

if let peopleData = defaults.data(forKey: "myPeopleData") as? [People] {
allPeopleList = peopleData
}
var allPeopleList = NSKeyedUnarchiver.unarchiveObject(with: peopleData!) as? [Peoples]

the xcode say it wrong

I recommend the Codable protocol and to save the data as JSON. It's swiftier than Obj-C related NSKeyed(Un)Archiver

  • Adopt the protocol

     class People : Codable { 
  • Encode the array as JSON and save it

     do { let newPeopleData = try JSONEncoder().encode(self.allPeopleList) self.defaults.set(newPeopleData, forKey: "myPeopleData") } catch { print(error) 
  • To read the data is very simple, too

     do { if let newPeopleData = self.defaults.data(forKey: "myPeopleData") { allPeopleList = try JSONDecoder().decode([People].self, from: newPeopleData) } } catch { print(error) 

Note: I'd name the class in singular form Person because an array of People ( [People] ) is tautologic and to name the properties image , time and name .

If you're using NSKeyedArchiver and NSKeyedUnarchiver , then the objects you archive must subclass NSObject and conform to NSCoding .

You'd have to do something like this:

class People: NSObject, NSCoding {

    let peopleImage : String
    let peopleTime : Int
    let peopleName : String

    init(image:String, second:Int, name:String) {
        peopleImage = image
        peopleTime = second
        peopleName = name
        super.init()
    }

    required init?(coder aDecoder: NSCoder) {
        self.peopleImage = aDecoder.decodeObject(forKey: "peopleImage") as! String
        self.peopleTime = aDecoder.decodeInteger(forKey: "peopleTime")
        self.peopleName = aDecoder.decodeObject(forKey: "peopleName") as! String
    }

    func encode(with aCoder: NSCoder) {
        aCoder.encode(self.peopleImage, forKey: "peopleImage")
        aCoder.encode(self.peopleTime, forKey: "peopleTime")
        aCoder.encode(self.peopleName, forKey: "peopleName")
    }
}

class CustomPeopleList: NSObject, NSCoding {

    var peopleList = [
        People(image: "Man", second: 12, name: "Andy"),
        People(image: "Woman", second: 60, name: "Kevin"),
    ]

    override init() {
        super.init()
    }

    required init?(coder aDecoder: NSCoder) {
        self.peopleList = aDecoder.decodeObject(forKey: "peopleList") as! [People]
    }

    func encode(with aCoder: NSCoder) {
        aCoder.encode(self.peopleList, forKey: "peopleList")
    }

}

var allPeopleList = CustomPeopleList()

let data = NSKeyedArchiver.archivedData(withRootObject: allPeopleList)

However

Implementing NSCoding can be very verbose.

If your objects include basic entities, like integers, strings, and arrays/dictionaries of encodable entities, then it may be easier to use Swift's new Codable protocol.

The advantage of this method is that if your objects are simple, then Swift can generate the encode and decode methods for you.

I personally recommend Codable . It can be much simpler than the old NSCoding method.

That would look like this:

class People: Codable {

    let peopleImage : String
    let peopleTime : Int
    let peopleName : String

    init(image:String, second:Int, name:String) {
        peopleImage = image
        peopleTime = second
        peopleName = name
    }
}

class CustomPeopleList: Codable {

    var peopleList = [
        People(image: "Man", second: 12, name: "Andy"),
        People(image: "Woman", second: 60, name: "Kevin"),
    ]

}

var allPeopleList = CustomPeopleList()

// Can save in whatever format you want. JSON is always light and simple.
let data = try JSONEncoder().encode(allPeopleList)

// Decode the data object later.
let decodedPeopleList = try JSONDecoder().decode(CustomPeopleList.self, from: data)

You need to inherit People class from NSObject when you are using NSKeyedUnarchiver or NSKeyedArchiver .

To store custom object in userdefaaults you need to inherit custom class form NSObject otherwise you will get runtime error/crashes.

class People: NSObject {


}

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