当在NSUserDefaults中存储自定义对象时,应用程序崩溃。

5

我有一个名为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 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)

1
你不能将自定义对象存储到NSUserDefaults中。 - vivek bhoraniya
1
@vivek,即使它符合NSCoding的要求? - rabbitinspace
我没有尝试过,但也许你的类必须基于NSObject?所以类User:NSObject,NSCoding。 - Volker
你能展示一下将对象添加到用户默认设置中的相关代码吗? - Volker
1
在将对象添加到用户默认设置之前,您必须将其转换为NSData,根据此处的答案进行相应操作https://dev59.com/UnE95IYBdhLWcg3wbtXO - Volker
显示剩余2条评论
1个回答

4

NSUserDefaults 不支持所有对象,只支持像 NSStringNSDictionary 和最重要的是 NSData 这样的对象。这就是 NSCoding 协议发挥作用的地方。它允许我们将自定义对象转换为一块块的 NSData。为了实现这个目的,使用 NSKeyedArchiver 类将符合 NSCoding 的自定义对象转换为等效的 NSData

let obj = User()
let data = NSKeyedArchiver. archivedDataWithRootObject(obj)
/// Now you can store data

文档可以在这里找到,您所需要的方法是

class func archivedDataWithRootObject(_ rootObject: AnyObject) -> NSData

要从NSUserDefaults中获取数据,可以使用"反序列化"类NSKeyedUnarchiver。它的适当方法如下所示。
class func unarchiveObjectWithData(_ data: NSData) -> AnyObject?

这里是一个示例。

let data = NSUserDefaults.standardUserDefaults().objectForKey("somekey")
let obj = NSKeyedUnarchiver. unarchiveObjectWithData(data) as User?

注意:我可能混淆了一些可选项,但你能理解我的意思。关于NSKeyedUnarchiver的文档可以在这里找到:这里。编辑:修复原帖的问题只需要正确使用NSKeyedArchiver并继承NSObject即可。

仍然不行。但我不明白为什么?截图 - rabbitinspace
@devnikor 你试过我的解决方案并且子类化了NSObject吗?这是我能想到的唯一方法。 - Brian Tracy
@devnikor 看看这个,它支持我的想法。http://www.touch-code-magazine.com/does-not-implement-methodsignatureforselector-trouble-ahead/ - Brian Tracy
1
终于!子类化NSObject和NSKeyedArchiver解决了它。谢谢。 - rabbitinspace

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接