[英]Swift saving and retrieving custom object from UserDefaults
我在 Playground 中使用 Swift 3,Xcode 8.0:
import Foundation
class Person: NSObject, NSCoding {
var name: String
var age: Int
init(name: String, age: Int) {
self.name = name
self.age = age
}
required convenience init(coder aDecoder: NSCoder) {
let name = aDecoder.decodeObject(forKey: "name") as! String
let age = aDecoder.decodeObject(forKey: "age") as! Int
self.init(
name: name,
age: age
)
}
func encode(with aCoder: NSCoder) {
aCoder.encode(name, forKey: "name")
aCoder.encode(age, forKey: "age")
}
}
斯威夫特 4 或更高版本
您可以再次在 Playground 中保存/測試您的值
UserDefaults 需要在實際項目中進行測試。 注意:無需強制同步。 如果你想在 Playground 中測試編碼/解碼,你可以使用 keyed archiver 將數據保存到文檔目錄中的 plist 文件中。 您還需要解決課堂上的一些問題:
class Person: NSObject, NSCoding {
let name: String
let age: Int
init(name: String, age: Int) {
self.name = name
self.age = age
}
required init(coder decoder: NSCoder) {
self.name = decoder.decodeObject(forKey: "name") as? String ?? ""
self.age = decoder.decodeInteger(forKey: "age")
}
func encode(with coder: NSCoder) {
coder.encode(name, forKey: "name")
coder.encode(age, forKey: "age")
}
}
測試:
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
do {
// setting a value for a key
let newPerson = Person(name: "Joe", age: 10)
var people = [Person]()
people.append(newPerson)
let encodedData = try NSKeyedArchiver.archivedData(withRootObject: people, requiringSecureCoding: false)
UserDefaults.standard.set(encodedData, forKey: "people")
// retrieving a value for a key
if let data = UserDefaults.standard.data(forKey: "people"),
let myPeopleList = try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data) as? [Person] {
myPeopleList.forEach({print($0.name, $0.age)}) // Joe 10
}
} catch {
print(error)
}
}
}
let age = aDecoder.decodeObject(forKey: "age") as! Int
Swift 3 已更改; 這不再適用於值類型。 現在正確的語法是:
let age = aDecoder.decodeInteger(forKey: "age")
有各種不同類型的相關 decode...() 函數:
let myBool = aDecoder.decodeBoolean(forKey: "myStoredBool")
let myFloat = aDecoder.decodeFloat(forKey: "myStoredFloat")
編輯: Swift 3 中所有可能的 decodeXXX 函數的完整列表
編輯:
另一個重要注意事項:如果您之前保存了使用舊版本 Swift 編碼的數據,則必須使用 decodeObject() 解碼這些值,但是一旦使用 encode(...) 重新編碼數據,它就不能再被如果它是值類型,則使用 decodeObject() 解碼。 因此,Markus Wyss 的回答將允許您處理使用任一 Swift 版本對數據進行編碼的情況:
self.age = aDecoder.decodeObject(forKey: "age") as? Int ?? aDecoder.decodeInteger(forKey: "age")
在 Swift 4 中:
您可以使用 Codable 從 Userdefaults 中保存和檢索自定義對象。 如果您經常這樣做,那么您可以添加為擴展名並像下面一樣使用它。
extension UserDefaults {
func save<T:Encodable>(customObject object: T, inKey key: String) {
let encoder = JSONEncoder()
if let encoded = try? encoder.encode(object) {
self.set(encoded, forKey: key)
}
}
func retrieve<T:Decodable>(object type:T.Type, fromKey key: String) -> T? {
if let data = self.data(forKey: key) {
let decoder = JSONDecoder()
if let object = try? decoder.decode(type, from: data) {
return object
}else {
print("Couldnt decode object")
return nil
}
}else {
print("Couldnt find key")
return nil
}
}
}
你的班級必須遵循 Codable。 它只是可編碼和可解碼協議的類型別名。
class UpdateProfile: Codable {
//Your stuffs
}
用法:
let updateProfile = UpdateProfile()
//To save the object
UserDefaults.standard.save(customObject: updateProfile, inKey: "YourKey")
//To retrieve the saved object
let obj = UserDefaults.standard.retrieve(object: UpdateProfile.self, fromKey: "YourKey")
有關更多編碼和解碼自定義類型,請查看Apple 的文檔。
試試這個:
self.age = aDecoder.decodeObject(forKey: "age") as? Int ?? aDecoder.decodeInteger(forKey: "age")
在 Swift 5 中,我會使用屬性包裝器來簡化代碼:
/// A type that adds an interface to use the user’s defaults with codable types
///
/// Example:
/// ```
/// @UserDefaultCodable(key: "nameKey", defaultValue: "Root") var name: String
/// ```
/// Adding the attribute @UserDefaultCodable the property works reading and writing from user's defaults
/// with any codable type
///
@propertyWrapper public struct UserDefaultCodable<T: Codable> {
private let key: String
private let defaultValue: T
/// Initialize the key and the default value.
public init(key: String, defaultValue: T) {
self.key = key
self.defaultValue = defaultValue
}
public var wrappedValue: T {
get {
// Read value from UserDefaults
guard let data = UserDefaults.standard.object(forKey: key) as? Data else {
// Return defaultValue when no data in UserDefaults
return defaultValue
}
// Convert data to the desire data type
let value = try? JSONDecoder().decode(T.self, from: data)
return value ?? defaultValue
}
set {
// Convert newValue to data
let data = try? JSONEncoder().encode(newValue)
// Set value to UserDefaults
UserDefaults.standard.set(data, forKey: key)
}
}
}
在UserDefaults中保存“自定義對象”的簡單示例如下:
您無需借助THE GREAT'CODABLE'編寫用於保存/檢索對象的樣板代碼,這就是您擺脫煩人的手動編碼/解碼的目的
因此,如果您已經在使用NSCoding並切換到Codable(Encodable + Decodable的組合)協議,請從代碼中刪除以下兩種方法
required init(coder decoder: NSCoder) // NOT REQUIRED ANY MORE, DECODABLE TAKES CARE OF IT
func encode(with coder: NSCoder) // NOT REQUIRED ANY MORE, ENCODABLE TAKES CARE OF IT
讓我們從Codable的簡單性入手...
創建要存儲在UserDefaults中的自定義類或結構
struct Person : Codable {
var name:String
}
OR
class Person : Codable {
var name:String
init(name:String) {
self.name = name
}
}
將對象保存在UserDefaults中,如下所示
if let encoded = try? JSONEncoder().encode(Person(name: "Dhaval")) {
UserDefaults.standard.set(encoded, forKey: "kSavedPerson")
}
從UserDefaults加載對象,如下所示
guard let savedPersonData = UserDefaults.standard.object(forKey: "kSavedPerson") as? Data else { return }
guard let savedPerson = try? JSONDecoder().decode(Person.self, from: savedPersonData) else { return }
print("\n Saved person name : \(savedPerson.name)")
而已 ...
保存/加載愉快.. :)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.