Ios 将结构保存为用户默认值
我有一个要保存为UserDefaults的结构。这是我的结构Ios 将结构保存为用户默认值,ios,swift,struct,nsuserdefaults,Ios,Swift,Struct,Nsuserdefaults,我有一个要保存为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
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,这样每当用户退出应用程序并再次打开它时,它就会被保存。我该怎么做?来自
默认对象必须是属性列表,即的实例(或集合的实例组合):
操作文件数据
,
NSString
,
数字对象
,
NSDate
,
不可变数组
或
字典
. 如果要存储任何其他类型的对象,通常应将其存档以创建NSData实例
您需要使用NSKeydArchiver
。您可以从中找到文档、示例和。
默认对象必须是属性列表,即的实例(或集合的实例组合):
操作文件数据
,
NSString
,
数字对象
,
NSDate
,
不可变数组
或
字典
. 如果要存储任何其他类型的对象,通常应将其存档以创建NSData实例
您需要使用
NSKeydArchiver
。如果您只是尝试将此歌曲数组保存为用户默认值,并且没有什么特别之处,则可以找到文档、示例和。:-
//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中的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")
}
}
如果您只是尝试在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中的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")
}
}
如果结构仅包含符合属性列表的属性,我建议添加属性
propertylisterepresentation
和相应的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
write
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) }
}
<> > <代码>标题<代码>和<代码>艺术家<代码>永远不会发生变化,考虑将属性声明为常量(<代码>让/<代码>)。< /P>
这个答案是在Swift 4处于测试状态时写的。同时,符合
Codable
是更好的解决方案。如果结构只包含符合属性列表的属性,我建议添加属性propertylisterepresentation
和相应的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
write
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) }
}
<> > <代码>标题<代码>和<代码>艺术家<代码>永远不会发生变化,考虑将属性声明为常量(<代码>让/<代码>)。< /P>
这个答案是在Swift 4处于测试状态时写的。同时,遵循
可编码的是更好的解决方案。在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.standard.set(try? PropertyListEncoder().encode(songs), forKey:"songs")
下面是如何在以后再次将其取出:
if let data = UserDefaults.standard.value(forKey:"songs") as? Data {
let songs2 = try? PropertyListDecoder().decode(Array<Song>.self, from: data)
}
如果let data=UserDefaults.standard.value(forKey:“songs”)为?资料{
let songs2=try?PropertyListDecoder().decode(Array.self,from:data)
}
在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.standard.set(try? PropertyListEncoder().encode(songs), forKey:"songs")
下面是如何在以后再次将其取出:
if let data = UserDefaults.standard.value(forKey:"songs") as? Data {
let songs2 = try? PropertyListDecoder().decode(Array<Song>.self, from: data)
}
如果let data=UserDefaults.standard.value(forKey:“songs”)为?资料{
let songs2=try?PropertyListDecoder().decode(Array.self,from:data)
}
这是我在主线程中的UserDefaults扩展,用于将getCodable对象设置为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)
}
}
// MARK: - JSONDecoder extensions
public extension JSONDecoder {
/// Decode an object, decoded from a JSON object.
///
/// - Parameter data: JSON object Data
/// - Returns: Decodable object
public func decode<T: Decodable>(from data: Data?) -> T? {
guard let data = data else {
return nil
}
return try? self.decode(T.self, from: data)
}
/// Decode an object in background thread, decoded from a JSON object.
///
/// - Parameters:
/// - data: JSON object Data
/// - onDecode: Decodable object
public func decodeInBackground<T: Decodable>(from data: Data?, onDecode: @escaping (T?) -> Void) {
DispatchQueue.global().async {
let decoded: T? = self.decode(from: data)
DispatchQueue.main.async {
onDecode(decoded)
}
}
}
}
// MARK: - JSONEncoder extensions
public extension JSONEncoder {
/// Encodable an object
///
/// - Parameter value: Encodable Object
/// - Returns: Data encode or nil
public func encode<T: Encodable>(from value: T?) -> Data? {
guard let value = value else {
return nil
}
return try? self.encode(value)
}
/// Encodable an object in background thread
///
/// - Parameters:
/// - encodableObject: Encodable Object
/// - onEncode: Data encode or nil
public func encodeInBackground<T: Encodable>(from encodableObject: T?, onEncode: @escaping (Data?) -> Void) {
DispatchQueue.global().async {
let encode = self.encode(from: encodableObject)
DispatchQueue.main.async {
onEncode(encode)
}
}
}
}
// MARK: - NSUserDefaults extensions
public extension UserDefaults {
/// Set Encodable object in UserDefaults
///
/// - Parameters:
/// - type: Encodable object type
/// - key: UserDefaults key
/// - Throws: An error if any value throws an error during encoding.
public func set<T: Encodable>(object type: T, for key: String, onEncode: @escaping (Bool) -> Void) throws {
JSONEncoder().encodeInBackground(from: type) { [weak self] (data) in
guard let data = data, let `self` = self else {
onEncode(false)
return
}
self.set(data, forKey: key)
onEncode(true)
}
}
/// Get Decodable object in UserDefaults
///
/// - Parameters:
/// - objectType: Decodable object type
/// - forKey: UserDefaults key
/// - onDecode: Codable object
public func get<T: Decodable>(object type: T.Type, for key: String, onDecode: @escaping (T?) -> Void) {
let data = value(forKey: key) as? Data
JSONDecoder().decodeInBackground(from: data, onDecode: onDecode)
}
}
//标记:-UserDefaults扩展名
公共扩展用户默认值{
///将可编码对象设置为UserDefaults
///
///-参数:
///-对象:可编码对象
///-福克:钥匙串
///-Throws:UserDefaults错误
公共函数集(对象:T,forKey:String)抛出{
让jsonData=try JSONEncoder().encode(对象)
集合(jsonData,forKey:forKey)
}
///将可编码对象获取到UserDefaults中
///
///-参数:
///-对象:可编码对象
///-福克:钥匙串
///-Throws:UserDefaults错误
公共函数get(objectType:T.Type,forKey:String)抛出->T{
guard let结果=值(forKey:forKey)作为?数据其他{
归零
}
返回try JSONDecoder().decode(objectType,from:result)
}
}
更新这是我的后台用户默认扩展,用于将getCodable对象设置为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)
}
}
// MARK: - JSONDecoder extensions
public extension JSONDecoder {
/// Decode an object, decoded from a JSON object.
///
/// - Parameter data: JSON object Data
/// - Returns: Decodable object
public func decode<T: Decodable>(from data: Data?) -> T? {
guard let data = data else {
return nil
}
return try? self.decode(T.self, from: data)
}
/// Decode an object in background thread, decoded from a JSON object.
///
/// - Parameters:
/// - data: JSON object Data
/// - onDecode: Decodable object
public func decodeInBackground<T: Decodable>(from data: Data?, onDecode: @escaping (T?) -> Void) {
DispatchQueue.global().async {
let decoded: T? = self.decode(from: data)
DispatchQueue.main.async {
onDecode(decoded)
}
}
}
}
// MARK: - JSONEncoder extensions
public extension JSONEncoder {
/// Encodable an object
///
/// - Parameter value: Encodable Object
/// - Returns: Data encode or nil
public func encode<T: Encodable>(from value: T?) -> Data? {
guard let value = value else {
return nil
}
return try? self.encode(value)
}
/// Encodable an object in background thread
///
/// - Parameters:
/// - encodableObject: Encodable Object
/// - onEncode: Data encode or nil
public func encodeInBackground<T: Encodable>(from encodableObject: T?, onEncode: @escaping (Data?) -> Void) {
DispatchQueue.global().async {
let encode = self.encode(from: encodableObject)
DispatchQueue.main.async {
onEncode(encode)
}
}
}
}
// MARK: - NSUserDefaults extensions
public extension UserDefaults {
/// Set Encodable object in UserDefaults
///
/// - Parameters:
/// - type: Encodable object type
/// - key: UserDefaults key
/// - Throws: An error if any value throws an error during encoding.
public func set<T: Encodable>(object type: T, for key: String, onEncode: @escaping (Bool) -> Void) throws {
JSONEncoder().encodeInBackground(from: type) { [weak self] (data) in
guard let data = data, let `self` = self else {
onEncode(false)
return
}
self.set(data, forKey: key)
onEncode(true)
}
}
/// Get Decodable object in UserDefaults
///
/// - Parameters:
/// - objectType: Decodable object type
/// - forKey: UserDefaults key
/// - onDecode: Codable object
public func get<T: Decodable>(object type: T.Type, for key: String, onDecode: @escaping (T?) -> Void) {
let data = value(forKey: key) as? Data
JSONDecoder().decodeInBackground(from: data, onDecode: onDecode)
}
}
//标记:-JSONDecoder扩展
公共扩展JSONDecoder{
///解码一个对象,从JSON对象解码。
///
///-参数数据:JSON对象数据
///-返回:可解码对象
公共函数解码(从数据:数据?->T{
guard let data=其他数据{
归零
}
返回try?self.decode(T.self,from:data)
}
///解码后台线程中的对象,从JSON对象解码。
///
///-参数:
///-data:JSON对象数据
///-onDecode:可解码对象
公共函数解码背景(来自数据:data?,onDecode:@escaping(T?)->Void){
DispatchQueue.global().async{
let decoded:T?=self.decode(from:data)
DispatchQueue.main.async{
编码(已解码)
}
}
}
}
//MARK:-JSONECODER扩展
公共扩展编码器{
///可编码的对象
///
///-参数值:可编码对象
///-返回:数据编码或零
公共函数编码(从值:T?)->