2017-07-03 71 views
9

我有一个结构,我想保存到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"), 
] 

在另一个视图控制器,我有一个附加到这个结构像

@IBAction func likeButtonPressed(_ sender: Any) { 

    songs.append(Song(title: songs[thisSong].title, artist: songs[thisSong].artist)) 

    } 

一个UIButton我想它,以便当用户点击该按钮也,其保存的结构来UserDefaults,以便每当用户退出应用程序,然后打开它,它被保存。我将如何做到这一点?

+0

检查https://stackoverflow.com/questions/28916535/swift-structs-to-nsdata-and-back – adev

+0

如果你正在尝试swift 4.有新的协议'Codable',这是很好的这种东西。对于较小的swift版本,您必须为您的结构创建字典并手动解析数据 – kathayatnk

回答

3

如果结构包含唯一的财产清单兼容的特性,我建议增加一个PROPERT Ÿ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.object(forKey: "songs") as? [[String:String]] { 
    songs = propertylistSongs.flatMap{ Song(dictionary: $0) } 
} 

如果titleartist永远不会发生突变考虑阵列将属性声明为常量(let)。


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

+0

我认为将'propertyListRepresentation'设置为'[String:Any]'可能会更好。 –

+0

@a_tuo为什么?这两种类型显然都是'String'。 Swift的强类型系统鼓励开发人员尽可能地使用类型。 – vadian

+0

如果在“Song”或其他类型中添加“var count:Int”,'[String:Any]'可能更具普遍性。这并不意味着它不安全。 –

0

here:

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

您需要使用NSKeydArchiver。可以找到文件here和示例herehere

1

如果你只是想挽回这个数组的歌曲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 

如果要存储一个沉重的阵列,我建议你用NSCoding协议或可编码的去协议编码协议的SWIFT 4

例子: -

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

} 
66

在Swift 4中,这非常简单。让你的结构可编码只需将其标记为采用可编码协议:

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

以下是如何在稍后再次取出:

​​
+0

这应该是正确的答案。 – Bobby

+2

得到错误,不能确认协议可编码 – Paragon