J'ai migré mon projet vers Swift 3 et NSKeyedArchiver
ne fonctionne pas. J'ai en fait une erreur d'exécution en essayant de décoder un objet comme celui-ci:
let startDayTime = aDecoder.decodeObject(forKey: Key.startDayTime) as! Int
Cela fonctionnait parfaitement dans Swift 2.2 dans Xcode 7.3. Quelqu'un at-il fait face à de tels problèmes?
P.S. J'ai cette erreur sur Simulator et Device.
UPDATE: J'ai résolu ce problème en utilisant decodeInteger(forKey key: String)
au lieu de decodeObject(forKey key: String)
. Pour une raison quelconque, AnyObject n’a pas recours à Integer dans Swift 3 contrairement à Swift 2.2
Il semble que cela ne se produise que sur la limite de mise à jour Swift 2 à Swift 3 lorsqu'un blob NSData archivé avec une variable NSKeyedArchiver
dans Swift 2 est ouvert avec une variable NSKeyedUnarchiver
dans Swift 3. Je suppose que sur Swift 2, les variables Bool
et Int
NSNumber
, mais dans Swift 3, ils sont codés en tant que types Bool
et Int
bruts. Je crois que le test suivant confirme cette affirmation:
Cela fonctionne dans Swift 3 pour désarchiver une Bool
encodée dans Swift 2, mais renvoie nil
si le booléen a été encodé dans Swift 3:
let visible = aDecoder.decodeObject(forKey: "visible") as? Bool
Cela fonctionne dans Swift 3 pour désarchiver une Bool
encodée dans Swift 3, mais se bloque si le booléen a été encodé dans Swift 2:
let visible = aDecoder.decodeBool(forKey: "visible")
Ma solution est:
let visible = aDecoder.decodeObject(forKey: "visible") as? Bool ?? aDecoder.decodeBool(forKey: "visible")
UPDATE: J'ai résolu ce problème en utilisant decodeInteger (forKey key: String) au lieu de decodeObject (forKey key: String). Pour une raison quelconque, AnyObject n’a pas recours à Integer dans Swift 3 contrairement à Swift 2.2
Voici la solution:
class Person: NSObject, NSCoding {
let name: String
let age: Int
required 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")
}}
Comment utiliser:
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
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")
if let data = UserDefaults.standard().data(forKey: "people"),
myPeopleList = NSKeyedUnarchiver.unarchiveObject(with: data) as? [Person] {
myPeopleList.forEach({print( $0.name, $0.age)}) // Joe 10
} else {
print("There is an issue")
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}}
Référence: Swift 3 enregistrer et récupérer un objet personnalisé à partir de userDefaults
Swift 3:
J'adopte la méthode {double point d'interrogation} _ ( ?? ) et fonctionne comme un charme sur une seule ligne.
Si val n'est pas nul, il est décompressé et la valeur renvoyée. Si elle est nulle, aDecoder.decodeInteger(forKey: "val")
est retourné:
self.val = aDecoder.decodeObject(forKey: "val") as? Int ?? aDecoder.decodeInteger(forKey: "val")