ios swift struct nsuserdefaults

ios - user defaults swift 4



Guardar Struct en UserDefaults (5)

Tengo una estructura que quiero guardar en UserDefaults. Aquí está mi estructura

struct Song { var title: String var artist: String } var songs: [Song] = [ Song(title: "Title 1", artist "Artist 1"), Song(title: "Title 2", artist "Artist 2"), Song(title: "Title 3", artist "Artist 3"), ]

En otro ViewController, tengo un UIButton que se agrega a esta estructura como

@IBAction func likeButtonPressed(_ sender: Any) { songs.append(Song(title: songs[thisSong].title, artist: songs[thisSong].artist)) }

Lo quiero para que cada vez que el usuario haga clic en ese botón, guarde la estructura en UserDefaults, de modo que cada vez que el usuario salga de la aplicación y luego la abra de nuevo, se guardará. ¿Cómo haría esto?


Desde here:

Un objeto predeterminado debe ser una lista de propiedades, es decir, una instancia de (o para colecciones, una combinación de instancias de): NSData, NSString, NSNumber, NSDate, NSArray o NSDictionary. Si desea almacenar cualquier otro tipo de objeto, normalmente debe archivarlo para crear una instancia de NSData.

Necesitas usar NSKeydArchiver . La documentación se puede encontrar here y ejemplos here y here .


En Swift 4 esto es bastante trivial. Haga que su estructura sea codificable simplemente marcándola como adoptando el protocolo Codable:

struct Song:Codable { var title: String var artist: String }

Ahora vamos a empezar con algunos datos:

var songs: [Song] = [ Song(title: "Title 1", artist: "Artist 1"), Song(title: "Title 2", artist: "Artist 2"), Song(title: "Title 3", artist: "Artist 3"), ]

Aquí es cómo conseguir que en UserDefaults:

UserDefaults.standard.set(try? PropertyListEncoder().encode(songs), forKey:"songs")

Y aquí está cómo volver a sacarlo más tarde:

if let data = UserDefaults.standard.value(forKey:"songs") as? Data { let songs2 = try? PropertyListDecoder().decode(Array<Song>.self, from: data) }


Esta es mi extensión UserDefaults , para establecer obtener el objeto Codable en UserDefaults

// MARK: - UserDefaults extensions public extension UserDefaults { /// Set Codable object into UserDefaults /// /// - Parameters: /// - object: Codable Object /// - forKey: Key string /// - Throws: UserDefaults Error public func set<T: Codable>(object: T, forKey: String) throws { let jsonData = try JSONEncoder().encode(object) set(jsonData, forKey: forKey) } /// Get Codable object into UserDefaults /// /// - Parameters: /// - object: Codable Object /// - forKey: Key string /// - Throws: UserDefaults Error public func get<T: Codable>(objectType: T.Type, forKey: String) throws -> T? { guard let result = value(forKey: forKey) as? Data else { return nil } return try JSONDecoder().decode(objectType, from: result) } }


Si la estructura solo contiene propiedades compatibles con la lista de propiedades, recomiendo agregar una propiedad propertyListRepresentation y un método init correspondiente

struct Song { var title: String var artist: String init(title : String, artist : String) { self.title = title self.artist = artist } init?(dictionary : [String:String]) { guard let title = dictionary["title"], let artist = dictionary["artist"] else { return nil } self.init(title: title, artist: artist) } var propertyListRepresentation : [String:String] { return ["title" : title, "artist" : artist] } }

Para guardar un conjunto de canciones en UserDefaults write

let propertylistSongs = songs.map{ $0.propertyListRepresentation } UserDefaults.standard.set(propertylistSongs, forKey: "songs")

Para leer la matriz

if let propertylistSongs = UserDefaults.standard.array(forKey: "songs") as? [[String:String]] { songs = propertylistSongs.flatMap{ Song(dictionary: $0) } }

Si el title y el artist nunca serán mutados, considere declarar las propiedades como constantes ( let ).

Esta respuesta se escribió mientras Swift 4 estaba en estado beta. Mientras tanto, conformarse con Codable es la mejor solución.


Si solo está intentando guardar este conjunto de canciones en UserDefaults y no hay nada especial, use esto:

//stores the array to defaults UserDefaults.standard.setValue(value: songs, forKey: "yourKey") //retrieving the array UserDefaults.standard.object(forKey: "yourKey") as! [Song] //Make sure to typecast this as an array of Song

Si está almacenando una matriz pesada, le sugiero que utilice el protocolo de codificación NSC o el protocolo codificable en swift 4

Ejemplo de protocolo de codificación: -

struct Song { var title: String var artist: String } class customClass: NSObject, NSCoding { //conform to nsobject and nscoding var songs: [Song] = [ Song(title: "Title 1", artist "Artist 1"), Song(title: "Title 2", artist "Artist 2"), Song(title: "Title 3", artist "Artist 3"), ] override init(arr: [Song]) self.songs = arr } required convenience init(coder aDecoder: NSCoder) { //decoding your array let songs = aDecoder.decodeObject(forKey: "yourKey") as! [Song] self.init(are: songs) } func encode(with aCoder: NSCoder) { //encoding aCoder.encode(songs, forKey: "yourKey") } }