Ich habe dies in Playground mit Swift 3, Xcode 8.0:
import Foundation
class Person: NSObject, NSCoding {
var name: String
var age: Int
init(name: String, age: Int) {
self.name = name
self.age = age
}
required convenience init(coder aDecoder: NSCoder) {
let name = aDecoder.decodeObject(forKey: "name") as! String
let age = aDecoder.decodeObject(forKey: "age") as! Int
self.init(
name: name,
age: age
)
}
func encode(with aCoder: NSCoder) {
aCoder.encode(name, forKey: "name")
aCoder.encode(age, forKey: "age")
}
}
array von Personen erstellen
let newPerson = Person(name: "Joe", age: 10)
var people = [Person]()
people.append(newPerson)
codiere das Array
let encodedData = NSKeyedArchiver.archivedData(withRootObject: people)
print("encodedData: \(encodedData))")
unter userDefaults speichern
let userDefaults: UserDefaults = UserDefaults.standard()
userDefaults.set(encodedData, forKey: "people")
userDefaults.synchronize()
prüfen
print("saved object: \(userDefaults.object(forKey: "people"))")
von userDefaults abrufen
if let data = userDefaults.object(forKey: "people") {
let myPeopleList = NSKeyedUnarchiver.unarchiveObject(with: data as! Data)
print("myPeopleList: \(myPeopleList)")
}else{
print("There is an issue")
}
überprüfen Sie einfach die archivierten Daten
if let myPeopleList = NSKeyedUnarchiver.unarchiveObject(with: encodedData){
print("myPeopleList: \(myPeopleList)")
}else{
print("There is an issue")
}
Ich kann das Datenobjekt nicht korrekt in userDefaults speichern. Außerdem wird bei der Überprüfung unten der Fehler "Schwerwiegender Fehler: Beim Auspacken eines optionalen Werts wurde unerwartet null gefunden" angezeigt. Die "Check" -Zeile zeigt auch, dass das gespeicherte Objekt Null ist. Ist dies ein Fehler im NSCoder meines Objekts?
Swift 4 Note
Sie können Ihre Werte erneut in einem Spielplatz speichern/testen
Swift
UserDefaults müssen in einem realen Projekt getestet werden. Hinweis: Sie müssen keine Synchronisierung erzwingen. Wenn Sie die Codierung/Decodierung auf einem Spielplatz testen möchten, können Sie die Daten mit dem verschlüsselten Archivierungsprogramm in einer plist-Datei im Dokumentenverzeichnis speichern. Sie müssen auch einige Probleme in Ihrer Klasse beheben:
class Person: NSObject, NSCoding {
let name: String
let age: Int
init(name: String, age: Int) {
self.name = name
self.age = age
}
required init(coder decoder: NSCoder) {
self.name = decoder.decodeObject(forKey: "name") as? String ?? ""
self.age = decoder.decodeInteger(forKey: "age")
}
func encode(with coder: NSCoder) {
coder.encode(name, forKey: "name")
coder.encode(age, forKey: "age")
}
}
Testen:
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// setting a value for a key
let newPerson = Person(name: "Joe", age: 10)
var people = [Person]()
people.append(newPerson)
let encodedData = NSKeyedArchiver.archivedData(withRootObject: people)
UserDefaults.standard.set(encodedData, forKey: "people")
// retrieving a value for a key
if let data = UserDefaults.standard.data(forKey: "people"),
let myPeopleList = NSKeyedUnarchiver.unarchiveObject(with: data) as? [Person] {
myPeopleList.forEach({print( $0.name, $0.age)}) // Joe 10
} else {
print("There is an issue")
}
}
}
let age = aDecoder.decodeObject(forKey: "age") as! Int
Dies wurde für Swift 3 geändert; dies funktioniert nicht mehr für Werttypen. Die korrekte Syntax lautet nun:
let age = aDecoder.decodeInteger(forKey: "age")
Es gibt zugehörige decode ... () -Funktionen für verschiedene Typen:
let myBool = aDecoder.decodeBoolean(forKey: "myStoredBool")
let myFloat = aDecoder.decodeFloat(forKey: "myStoredFloat")
Edit: Vollständige Liste aller möglichen decodeXXX-Funktionen in Swift
Bearbeiten:
Ein weiterer wichtiger Hinweis: Wenn Sie zuvor Daten gespeichert haben, die mit einer älteren Version von Swift kodiert wurden, müssen diese Werte mit decodeObject () dekodiert werden , jedoch Sobald Sie die Daten mit encode (...) neu codieren, können sie nicht mehr mit decodeObject () decodiert werden, wenn es sich um einen Werttyp handelt. Aus diesem Grund können Sie mit der Antwort von Markus Wyss den Fall behandeln, in dem die Daten entweder mit Swift version:
self.age = aDecoder.decodeObject(forKey: "age") as? Int ?? aDecoder.decodeInteger(forKey: "age")
Versuche dies:
self.age = aDecoder.decodeObject(forKey: "age") as? Int ?? aDecoder.decodeInteger(forKey: "age")
In Swift 4:
Sie können Codable zum Speichern und Abrufen von benutzerdefinierten Objekten aus den Benutzervorgaben verwenden. Wenn Sie es häufig tun, können Sie es wie unten beschrieben als Erweiterung hinzufügen und verwenden.
extension UserDefaults {
func save<T:Encodable>(customObject object: T, inKey key: String) {
let encoder = JSONEncoder()
if let encoded = try? encoder.encode(object) {
self.set(encoded, forKey: key)
}
}
func retrieve<T:Decodable>(object type:T.Type, fromKey key: String) -> T? {
if let data = self.data(forKey: key) {
let decoder = JSONDecoder()
if let object = try? decoder.decode(type, from: data) {
return object
}else {
print("Couldnt decode object")
return nil
}
}else {
print("Couldnt find key")
return nil
}
}
}
Ihre Klasse muss Codable folgen. Es ist nur ein typealias für Encodable & Decodable Protocol.
class UpdateProfile: Codable {
//Your stuffs
}
Verwendung:
let updateProfile = UpdateProfile()
//To save the object
UserDefaults.standard.save(customObject: updateProfile, inKey: "YourKey")
//To retrieve the saved object
let obj = UserDefaults.standard.retrieve(object: UpdateProfile.self, fromKey: "YourKey")
Weitere Informationen zum Kodieren und Dekodieren benutzerdefinierter Typen finden Sie in der Dokumentation zu Apple .