Swift: 用UserDefaults保存复杂对象
一直木有看过这个细节,用UserDefaults是能不能存复杂一点的对象。大家可能都看到过UserDefaults的一个方法 偶然一次直接存了一个继承自 The value parameter can be only property list objects: NSData,NSString,NSNumber,NSDate,NSArray,or NSDictionary. For NSArray and NSDictionary objects,their contents must be property list objects.
简单来说就是 既然苹果的API已经限制到这个地步了再想别的已经玩不出什么花样了。是的,你可以存文件。不过这里说的还是用UserDefaults嘛。 解决这个问题的核心思想就是把一个对象转换为 //假设有一个用户实体类
class UserModel {
var userId: String = ""
var accessToken: String = ""
}
//然后
let userModel = UserModel()
//正式开始
let userDefaults = NSUserDefaults.standardUserDefaults()
let encodedObject = NSKeyedArchiver.archivedDataWithRootObject(object)
userDefaults.setObject(encodedObject,forKey: "UserInfoKey")
userDefaults.synchronize() //最后不要忘了这个
大体的意思在上面的代码中全部都体现出来了。但是如果运行上面的代码肯定是会出错的。 *** Terminating app due to uncaught exception 'NSInvalidArgumentException',reason: 'Attempt to insert non-property list object UserModel for key UserInfoKey'
因为不是property list object所以执行方法 这个问题看似就在property list object上了。但是回到什么说的,我们的思路是把这个自定义的实体类的对象转化为 对上面的代码做一次小小的改进: class WeiboUserModel: NSObject,NSCoding { //1
struct PropertyKey {
static let userIdKey = "userId"
static let accessTokenKey = "accessToken"
static let expirationDateKey = "expirationDate"
static let refreshTokenKey = "refreshToken"
}
var userId: String?
var accessToken: String?
var expirationDate: NSDate?
var refreshToken: String?
func encodeWithCoder(aCoder: NSCoder) { //2
aCoder.encodeObject(userId,forKey: PropertyKey.userIdKey)
aCoder.encodeObject(accessToken,forKey: PropertyKey.accessTokenKey)
aCoder.encodeObject(expirationDate,forKey: PropertyKey.expirationDateKey)
aCoder.encodeObject(refreshToken,forKey: PropertyKey.refreshTokenKey)
}
required init?(coder aDecoder: NSCoder) { // 3
userId = aDecoder.decodeObjectForKey(PropertyKey.userIdKey) as? String
accessToken = aDecoder.decodeObjectForKey(PropertyKey.accessTokenKey) as? String
expirationDate = aDecoder.decodeObjectForKey(PropertyKey.expirationDateKey) as? NSDate
refreshToken = aDecoder.decodeObjectForKey(PropertyKey.refreshTokenKey) as? String
}
}
如此的修改就可以让他们跑起来了。下面依次解释: 在大体逻辑不修改的条件下,我们看下完整的可以存实体类对象的代码。 //然后
let userModel = WeiboUserModel()
//正式开始
let userDefaults = NSUserDefaults.standardUserDefaults()
let encodedObject = NSKeyedArchiver.archivedDataWithRootObject(object)
userDefaults.setObject(encodedObject,forKey: "UserInfoKey")
userDefaults.synchronize() //最后不要忘了这个
这样就可以运行了。但是我们不能止步于此。因为如果项目中需要保存的地方太多的时候,到处都写满了(极有可能是复制粘贴) 所以我们要对这一部分的代码做一定的封装: extension NSUserDefaults { //1
func saveCustomObject(customObject object: NSCoding,key: String) { //2
let encodedObject = NSKeyedArchiver.archivedDataWithRootObject(object)
self.setObject(encodedObject,forKey: key)
self.synchronize()
}
func getCustomObject(forKey key: String) -> AnyObject? { //3
let decodedObject = self.objectForKey(key) as? NSData
if let decoded = decodedObject {
let object = NSKeyedUnarchiver.unarchiveObjectWithData(decoded)
return object
}
return nil
}
}
我们把存取的方法都放在 userDefaults.saveCustomObject(customObject: userModel,key: "UserInfoKey") //存
userDefaults.getCustomObject("UserInfoKey") as? WeiboUserModel //取
好的,到这。完整项目的代码请移步这里。 to be continued(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |