将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) } }
如果title
和artist
永远不会被改变,请考虑将属性声明为常量( 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
。 可在此处和此处找到文档和示例。