63 votes

Swift 3 enregistrer et récupérer un objet personnalisé à partir de userDefaults

J'ai cela en Aire de jeu à l'aide de 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")
    }
}

créer la matrice de la Personne

let newPerson = Person(name: "Joe", age: 10)
var people = [Person]()
people.append(newPerson)

coder le tableau

let encodedData = NSKeyedArchiver.archivedData(withRootObject: people)
print("encodedData: \(encodedData))")

enregistrer pour userDefaults

let userDefaults: UserDefaults = UserDefaults.standard()
userDefaults.set(encodedData, forKey: "people")
userDefaults.synchronize()

vérifier

print("saved object: \(userDefaults.object(forKey: "people"))")

récupérer à partir de userDefaults

if let data = userDefaults.object(forKey: "people") {
    let myPeopleList = NSKeyedUnarchiver.unarchiveObject(with: data as! Data)
    print("myPeopleList: \(myPeopleList)")
}else{
    print("There is an issue")
}

il suffit de consulter les données archivées

if let myPeopleList = NSKeyedUnarchiver.unarchiveObject(with: encodedData){
   print("myPeopleList: \(myPeopleList)")
}else{
   print("There is an issue")
}

Je ne suis pas en mesure d'enregistrer correctement les données de l'objet à userDefaults, et en plus, la case en bas crée l'erreur "fatal error: de façon inattendue trouvé nulle, tandis que d'ôter une valeur Facultative". Le "check" de la ligne de montre également enregistrées objet est nul. Est-ce une erreur dans mon objet NSCoder?

92voto

Leo Dabus Points 122890

Swift 4 Note

Vous pouvez à nouveau sauvegarder / tester vos valeurs dans un terrain de jeu.


Swift 3

UserDefaults doivent être testés dans un projet réel. Remarque: pas besoin de forcer la synchronisation. Si vous souhaitez tester le codage / décodage dans un terrain de jeu, vous pouvez enregistrer les données dans un fichier Plist du répertoire de documents à l’aide de l’archiveur à clé. Vous devez également résoudre certains problèmes dans votre classe:

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

Essai:

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

49voto

ibuprofane Points 620
let age = aDecoder.decodeObject(forKey: "age") as! Int

Cela a été modifié pour la Swift 3; cela ne fonctionne plus pour les types de valeur. La syntaxe correcte est maintenant:

let age = aDecoder.decodeInteger(forKey: "age")

Y sont associés décoder...() les fonctions de différents types:

let myBool = aDecoder.decodeBoolean(forKey: "myStoredBool")
let myFloat = aDecoder.decodeFloat(forKey: "myStoredFloat")

Edit: la liste Complète de tous les possibles decodeXXX fonctions Swift 3

Edit:

Une autre remarque importante: Si vous avez précédemment enregistré les données qui ont été codées avec une ancienne version de Swift, ces valeurs doivent être décodés à l'aide de decodeObject(), cependant une fois que vous ré-encoder les données à l'aide de coder (...), il ne peut plus être décodé avec decodeObject() si c'est un type de valeur. Par conséquent, Markus Wyss la réponse va vous permettre de gérer le cas où les données ont été codées en utilisant soit Swift version:

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

12voto

mswyss Points 225

Essaye ça:

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X