swift3 - NSKeyedArchiver no funciona en Swift 3(XCode 8)
xcode8 ios10 (4)
ACTUALIZACIÓN: Resolví este problema usando decodeInteger (forKey key: String) en lugar de decodeObject (forKey key: String). Por alguna razón, AnyObject no se convierte en Integer en Swift 3, aunque sí en Swift 2.2
He migrado mi proyecto a Swift 3 y NSKeyedArchiver
no funciona. De hecho, tengo un error de tiempo de ejecución al intentar decodificar un objeto como este:
let startDayTime = aDecoder.decodeObject(forKey: Key.startDayTime) as! Int
Funcionó perfectamente en Swift 2.2 en Xcode 7.3. ¿Alguien más ha enfrentado tales problemas?
PS Tengo este error tanto en el simulador como en el dispositivo.
ACTUALIZACIÓN: decodeInteger(forKey key: String)
este problema usando decodeInteger(forKey key: String)
lugar de decodeObject(forKey key: String)
. Por alguna razón, AnyObject no se convierte en Integer en Swift 3, aunque sí en Swift 2.2
Aquí está la solución:
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")
}}
Cómo utilizar:
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()
}}
Referencia: Swift 3 guardando y recuperando objetos personalizados de userDefaults
Parece que esto solo sucede en el límite de actualización de Swift 2 a Swift 3 cuando un blob NSData archivado con un NSKeyedArchiver
en Swift 2 se abre con un NSKeyedUnarchiver
en Swift 3. Mi opinión es que en Swift 2, Bool
e Int
están codificados como NSNumber
, pero en Swift 3, están codificados como tipos Bool
e Int
sin Bool
. Creo que la siguiente prueba apoya esta afirmación:
Esto funciona en Swift 3 para desarchivar un Bool
codificado en Swift 2, pero devuelve nil
si el Bool fue codificado en Swift 3:
let visible = aDecoder.decodeObject(forKey: "visible") as? Bool
Esto funciona en Swift 3 para desarchivar un Bool
codificado en Swift 3, pero se bloquea si el Bool fue codificado en Swift 2:
let visible = aDecoder.decodeBool(forKey: "visible")
Mi solución es:
let visible = aDecoder.decodeObject(forKey: "visible") as? Bool ?? aDecoder.decodeBool(forKey: "visible")
Swift 3 :
Adopto el método del signo de interrogación doble ( ?? ) y funciona como un hechizo en una sola línea .
Si val no es nulo, se desempaqueta y se devuelve el valor. Si es nulo, aDecoder.decodeInteger(forKey: "val")
devuelve:
self.val = aDecoder.decodeObject(forKey: "val") as? Int ?? aDecoder.decodeInteger(forKey: "val")