在 NSUserDefaults 中存储自定义对象时应用程序崩溃
App crashes when storing custom object in NSUserDefaults
我有自定义 class 命名为 User
符合 NSCoding 协议。但是当我试图将它存储在 NSUserDefaults 中时,我得到了这个错误:
Property list invalid for format: 200
(property lists cannot contain objects of type 'CFType')
还有这个警告:
NSForwarding: warning: object 0x7f816a681110 of class 'Shikimori.User'
does not implement methodSignatureForSelector: -- trouble ahead
Unrecognized selector -[Shikimori.User _copyDescription]
User
class:
class User: NSCoding {
private enum CoderKeys: String {
case ID = "user.id"
case Username = "user.username"
case Email = "user.email"
case Avatar = "user.avatar"
}
let id: Int
let username: String
let email: String
let avatar: String
init(id: Int, username: String, email: String, avatar: String) {
self.id = id
self.username = username
self.email = email
self.avatar = avatar
}
required init(coder aDecoder: NSCoder) {
id = aDecoder.decodeIntegerForKey(CoderKeys.ID.rawValue)
username = aDecoder.decodeObjectForKey(CoderKeys.Username.rawValue) as String
email = aDecoder.decodeObjectForKey(CoderKeys.Email.rawValue) as String
avatar = aDecoder.decodeObjectForKey(CoderKeys.Avatar.rawValue) as String
}
func encodeWithCoder(aCoder: NSCoder) {
aCoder.encodeInteger(id, forKey: CoderKeys.ID.rawValue)
aCoder.encodeObject(username as NSString, forKey: CoderKeys.Username.rawValue)
aCoder.encodeObject(email as NSString, forKey: CoderKeys.Email.rawValue)
aCoder.encodeObject(avatar as NSString, forKey: CoderKeys.Avatar.rawValue)
}
}
更新
保存代码:
let userKeyForDefaults = "apimanager.user"
let defaults = NSUserDefaults.standardUserDefaults()
defaults.setObject(user, forKey: self.userKeyForDefaults)
NSUserDefaults
不支持所有对象,只支持 NSString
、NSDictionary
,最重要的是 NSData
。这就是 NSCoding
协议派上用场的地方。它允许我们将自定义对象转换为 NSData
的块。为此,请使用 NSKeyedArchiver
class 将符合 NSCoding
的自定义对象转换为等效的 NSData
let obj = User()
let data = NSKeyedArchiver. archivedDataWithRootObject(obj)
/// Now you can store data
可以找到文档here,您要查找的方法是
class func archivedDataWithRootObject(_ rootObject: AnyObject) -> NSData
要获取 out 的 NSUserDefaults
,请使用 "inverse" class、NSKeyedUnarchiver
。其合适的方法如下
class func unarchiveObjectWithData(_ data: NSData) -> AnyObject?
这是一个示例。
let data = NSUserDefaults.standardUserDefaults().objectForKey("somekey")
let obj = NSKeyedUnarchiver. unarchiveObjectWithData(data) as User?
注意:我可能混淆了一些选项,但你明白了。 NSKeyedUnarchiver
的文档可以在 here.
中找到
编辑:修复 OP 的问题就像正确使用 NSKeyedArchiver
和 subclassing NSObject
.
一样简单
我有自定义 class 命名为 User
符合 NSCoding 协议。但是当我试图将它存储在 NSUserDefaults 中时,我得到了这个错误:
Property list invalid for format: 200
(property lists cannot contain objects of type 'CFType')
还有这个警告:
NSForwarding: warning: object 0x7f816a681110 of class 'Shikimori.User'
does not implement methodSignatureForSelector: -- trouble ahead
Unrecognized selector -[Shikimori.User _copyDescription]
User
class:
class User: NSCoding {
private enum CoderKeys: String {
case ID = "user.id"
case Username = "user.username"
case Email = "user.email"
case Avatar = "user.avatar"
}
let id: Int
let username: String
let email: String
let avatar: String
init(id: Int, username: String, email: String, avatar: String) {
self.id = id
self.username = username
self.email = email
self.avatar = avatar
}
required init(coder aDecoder: NSCoder) {
id = aDecoder.decodeIntegerForKey(CoderKeys.ID.rawValue)
username = aDecoder.decodeObjectForKey(CoderKeys.Username.rawValue) as String
email = aDecoder.decodeObjectForKey(CoderKeys.Email.rawValue) as String
avatar = aDecoder.decodeObjectForKey(CoderKeys.Avatar.rawValue) as String
}
func encodeWithCoder(aCoder: NSCoder) {
aCoder.encodeInteger(id, forKey: CoderKeys.ID.rawValue)
aCoder.encodeObject(username as NSString, forKey: CoderKeys.Username.rawValue)
aCoder.encodeObject(email as NSString, forKey: CoderKeys.Email.rawValue)
aCoder.encodeObject(avatar as NSString, forKey: CoderKeys.Avatar.rawValue)
}
}
更新 保存代码:
let userKeyForDefaults = "apimanager.user"
let defaults = NSUserDefaults.standardUserDefaults()
defaults.setObject(user, forKey: self.userKeyForDefaults)
NSUserDefaults
不支持所有对象,只支持 NSString
、NSDictionary
,最重要的是 NSData
。这就是 NSCoding
协议派上用场的地方。它允许我们将自定义对象转换为 NSData
的块。为此,请使用 NSKeyedArchiver
class 将符合 NSCoding
的自定义对象转换为等效的 NSData
let obj = User()
let data = NSKeyedArchiver. archivedDataWithRootObject(obj)
/// Now you can store data
可以找到文档here,您要查找的方法是
class func archivedDataWithRootObject(_ rootObject: AnyObject) -> NSData
要获取 out 的 NSUserDefaults
,请使用 "inverse" class、NSKeyedUnarchiver
。其合适的方法如下
class func unarchiveObjectWithData(_ data: NSData) -> AnyObject?
这是一个示例。
let data = NSUserDefaults.standardUserDefaults().objectForKey("somekey")
let obj = NSKeyedUnarchiver. unarchiveObjectWithData(data) as User?
注意:我可能混淆了一些选项,但你明白了。 NSKeyedUnarchiver
的文档可以在 here.
编辑:修复 OP 的问题就像正确使用 NSKeyedArchiver
和 subclassing NSObject
.