Jac*_*vin 50 struct nsuserdefaults ios swift
我有一个结构,我想保存到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"),
]
Run Code Online (Sandbox Code Playgroud)
在另一个ViewController中,我有一个附加到这个结构的UIButton
@IBAction func likeButtonPressed(_ sender: Any) {
songs.append(Song(title: songs[thisSong].title, artist: songs[thisSong].artist))
}
Run Code Online (Sandbox Code Playgroud)
我想要它,以便每当用户也点击该按钮时,它会将结构保存到UserDefaults,这样每当用户退出应用程序然后打开它时,它就会被保存.我该怎么做?
mat*_*att 220
在Swift 4中,这几乎是微不足道的.通过将其标记为采用Codable协议,使您的结构可编码:
struct Song:Codable {
var title: String
var artist: String
}
Run Code Online (Sandbox Code Playgroud)
现在让我们从一些数据开始:
var songs: [Song] = [
Song(title: "Title 1", artist: "Artist 1"),
Song(title: "Title 2", artist: "Artist 2"),
Song(title: "Title 3", artist: "Artist 3"),
]
Run Code Online (Sandbox Code Playgroud)
以下是如何将其纳入UserDefaults:
UserDefaults.standard.set(try? PropertyListEncoder().encode(songs), forKey:"songs")
Run Code Online (Sandbox Code Playgroud)
以下是如何让它再次退出:
if let data = UserDefaults.standard.value(forKey:"songs") as? Data {
let songs2 = try? PropertyListDecoder().decode(Array<Song>.self, from: data)
}
Run Code Online (Sandbox Code Playgroud)
Yan*_*eph 17
这是我在主线程中的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<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)
}
}
Run Code Online (Sandbox Code Playgroud)
更新这是我在后台的UserDefaults扩展,将get Codable对象设置为UserDefaults
// 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)
}
}
Run Code Online (Sandbox Code Playgroud)
vad*_*ian 14
如果结构只包含属性列表兼容属性,我建议添加属性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]
}
}
Run Code Online (Sandbox Code Playgroud)
保存要UserDefaults编写的歌曲数组
let propertylistSongs = songs.map{ $0.propertyListRepresentation }
UserDefaults.standard.set(propertylistSongs, forKey: "songs")
Run Code Online (Sandbox Code Playgroud)
要读取数组
if let propertylistSongs = UserDefaults.standard.array(forKey: "songs") as? [[String:String]] {
songs = propertylistSongs.flatMap{ Song(dictionary: $0) }
}
Run Code Online (Sandbox Code Playgroud)
如果title且artist永远不会发生变异,请考虑将属性声明为常量(let).
这个答案是在Swift 4处于测试状态时编写的.同时符合Codable是更好的解决方案.
这是一个现代的 Swift 5.1 @propertyWrapper,允许以Codable人类可读的 JSON 字符串的形式存储任何对象:
@propertyWrapper struct UserDefaultEncoded<T: Codable> {
let key: String
let defaultValue: T
init(key: String, default: T) {
self.key = key
defaultValue = `default`
}
var wrappedValue: T {
get {
guard let jsonString = UserDefaults.standard.string(forKey: key) else {
return defaultValue
}
guard let jsonData = jsonString.data(using: .utf8) else {
return defaultValue
}
guard let value = try? JSONDecoder().decode(T.self, from: jsonData) else {
return defaultValue
}
return value
}
set {
let encoder = JSONEncoder()
encoder.outputFormatting = [.prettyPrinted, .sortedKeys]
guard let jsonData = try? encoder.encode(newValue) else { return }
let jsonString = String(bytes: jsonData, encoding: .utf8)
UserDefaults.standard.set(jsonString, forKey: key)
}
}
}
Run Code Online (Sandbox Code Playgroud)
用法:
extension Song: Codable {}
@UserDefaultEncoded(key: "songs", default: [])
var songs: [Song]
func addSong(_ song: Song) {
// This will automatically store new `songs` value
// to UserDefaults
songs.append(song)
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
22546 次 |
| 最近记录: |