webentwicklung-frage-antwort-db.com.de

Swift 3 Speichern und Abrufen von benutzerdefinierten Objekten aus userDefaults

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?

60
user773881

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")
        }
    }
}
89
Leo Dabus
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")
49
ibuprofane

Versuche dies:

self.age = aDecoder.decodeObject(forKey: "age") as? Int ?? aDecoder.decodeInteger(forKey: "age")
11
mswyss

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 .

6
Bishow Gurung