将Struct保存到UserDefaults

我有一个结构,我想保存到UserDefaults。 这是我的结构

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"), ] 

在另一个ViewController中,我有一个UIButton,它附加到这个结构上

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

我想要它,以便每当用户也点击该按钮时,它会将结构保存到UserDefaults,这样每当用户退出应用程序然后打开它时,它就会被保存。 我该怎么办?

在Swift 4中,这几乎是微不足道的。 通过将其标记为采用Codable协议,使您的结构可编码:

 struct Song:Codable { 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"), ] 

以下是如何将其纳入UserDefaults:

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

以下是如何让它再次退出:

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

如果struct只包含属性列表兼容属性,我建议添加属性propertyListRepresentation和相应的init方法

 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] } } 

将一组歌曲保存到UserDefaults写入

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

要读取数组

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

如果titleartist永远不会被改变,请考虑将属性声明为常量( let )。


这个答案是在Swift 4处于测试状态时编写的。 同时符合Codable是更好的解决方案。

这是我的UserDefaults扩展 ,将get Codable对象设置为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(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(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) } } 

如果您只是想在UserDefaults中保存这一系列歌曲而没有任何花哨的用法: –

 //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 

如果你要存储一个重型arrays,我建议你使用swift 4中的NSCoding协议或Codable协议

编码协议示例: –

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

从这里:

默认对象必须是属性列表 – 即(或集合,实例的组合)的实例:NSData,NSString,NSNumber,NSDate,NSArray或NSDictionary。 如果要存储任何其他类型的对象,通常应将其存档以创建NSData实例。

您需要使用NSKeydArchiver 。 可在此处和此处找到文档和示例。