Guardar clase Swift personalizada con NSCoding en UserDefaults

Resuelto The Lone Coder asked hace 10 años • 12 respuestas

Actualmente estoy intentando guardar una clase Swift personalizada en NSUserDefaults. Aquí está el código de mi Playground:

import Foundation

class Blog : NSObject, NSCoding {

    var blogName: String?

    override init() {}

    required init(coder aDecoder: NSCoder) {
        if let blogName = aDecoder.decodeObjectForKey("blogName") as? String {
            self.blogName = blogName
        }
    }

    func encodeWithCoder(aCoder: NSCoder) {
        if let blogName = self.blogName {
            aCoder.encodeObject(blogName, forKey: "blogName")
        }
    }

}

var blog = Blog()
blog.blogName = "My Blog"

let ud = NSUserDefaults.standardUserDefaults()    
ud.setObject(blog, forKey: "blog")

Cuando ejecuto el código, aparece el siguiente error

La ejecución fue interrumpida, motivo: señal SIGABRT.

en la última línea ( ud.setObject...)

El mismo código también falla cuando está en una aplicación con el mensaje

"La lista de propiedades no es válida para el formato: 200 (las listas de propiedades no pueden contener objetos del tipo 'CFType')"

¿Alguien puede ayudar? Estoy usando Xcode 6.0.1 en Maverick. Gracias.

The Lone Coder avatar Oct 20 '14 22:10 The Lone Coder
Aceptado

En Swift 4 o superior, use codificable.

En su caso, utilice el siguiente código.

class Blog: Codable {
   var blogName: String?
}

Ahora crea su objeto. Por ejemplo:

var blog = Blog()
blog.blogName = "My Blog"

Ahora codificalo así:

if let encoded = try? JSONEncoder().encode(blog) {
    UserDefaults.standard.set(encoded, forKey: "blog")
}

y decodificarlo así:

if let blogData = UserDefaults.standard.data(forKey: "blog"),
    let blog = try? JSONDecoder().decode(Blog.self, from: blogData) {
}
Ghulam Rasool avatar Mar 27 '2018 19:03 Ghulam Rasool

El primer problema es que debes asegurarte de tener un nombre de clase que no esté alterado:

@objc(Blog)
class Blog : NSObject, NSCoding {

Luego debe codificar el objeto (en un NSData) antes de poder almacenarlo en los valores predeterminados del usuario:

ud.setObject(NSKeyedArchiver.archivedDataWithRootObject(blog), forKey: "blog")

De manera similar, para restaurar el objeto necesitarás desarchivarlo:

if let data = ud.objectForKey("blog") as? NSData {
    let unarc = NSKeyedUnarchiver(forReadingWithData: data)
    unarc.setClass(Blog.self, forClassName: "Blog")
    let blog = unarc.decodeObjectForKey("root")
}

Ten en cuenta que si no lo estás usando en el patio de recreo es un poco más sencillo ya que no tienes que registrar la clase manualmente:

if let data = ud.objectForKey("blog") as? NSData {
    let blog = NSKeyedUnarchiver.unarchiveObjectWithData(data)
}
David Berry avatar Oct 20 '2014 16:10 David Berry