【发布时间】:2016-02-12 04:02:43
【问题描述】:
我正在阅读其他一些帖子,但我似乎无法弄清楚为什么在下面使用 NSKeyedUnarchiver 保存到磁盘的对象总是在控制台打印空行。我的最终目标是使用 NSKeyedArchiver 将单个用户对象存储到磁盘。
我目前正在学习如何使用 Firebase 来存储一些数据。我有一个代表用户的自定义类,如下所示:
class User: NSObject, NSCoding {
let key: String
let email: String
let familyKey: String
let username: String
let provider: String
let role: String
// Initialize from arbitrary data
init(key: String, email: String, fKey: String, uName:String, provider:String, role: String) {
self.key = key
self.email = email
self.familyKey = fKey
self.username = uName
self.provider = provider
self.role = role
super.init()
}
required init?(coder aDecoder: NSCoder) {
self.key = aDecoder.valueForKey("key") as! String
self.email = aDecoder.valueForKey("email") as! String
self.familyKey = aDecoder.valueForKey("familyKey") as! String
self.username = aDecoder.valueForKey("username") as! String
self.provider = aDecoder.valueForKey("provider") as! String
self.role = aDecoder.valueForKey("role") as! String
}
func encodeWithCoder(aCoder: NSCoder) {
aCoder.encodeObject(self.key, forKey: "key")
aCoder.encodeObject(self.email, forKey: "email")
aCoder.encodeObject(self.familyKey, forKey: "familyKey")
aCoder.encodeObject(self.username, forKey: "username")
aCoder.encodeObject(self.provider, forKey: "provider")
aCoder.encodeObject(self.role, forKey: "role")
}
在我的注册视图控制器中,我创建用户并使用 Firebase 对用户进行身份验证,没有任何问题。在身份验证块中,我使用上面的第一个自定义初始化程序初始化用户对象。我已经尝试了以下方法来保存它,所以我相信我的问题在于我上面的代码与数据的编码/解码,因为这些都不起作用。
基于来自HackingWithSwift 的此链接在本地存档文件。 FBPath.shared.docDir 只是一个指向我的文档目录的 NSString 链接。
let userPath = FBPath.shared.docDir.stringByAppendingPathComponent("currentUser")
let userData = NSKeyedArchiver.archivedDataWithRootObject(newUser)
userData.writeToFile(userPath, atomically: true)
尝试使用
检索此内容let userPath = FBPath.shared.docDir.stringByAppendingPathComponent("currentUser")
if let user = NSKeyedUnarchiver.unarchiveObjectWithFile(userPath) as? User {
print(user.username)
}
这不起作用,所以我尝试使用来自 Whasssaaahhh 的帖子将其存储到磁盘上 post by Whasssaaahhh。这是实际工作的代码,但存储了一个 emtpy 文件。
required convenience init?(coder aDecoder: NSCoder) {
guard let aKey = aDecoder.decodeObjectForKey("userKey") as? String else {return nil}
guard let anEmail = aDecoder.decodeObjectForKey("userEmail") as? String else {return nil}
guard let aFamilyKey = aDecoder.decodeObjectForKey("usersFamilyKey") as? String else {return nil}
guard let userName = aDecoder.decodeObjectForKey("username") as? String else {return nil}
guard let aProvider = aDecoder.decodeObjectForKey("userProvider") as? String else {return nil}
guard let aRole = aDecoder.decodeObjectForKey("userRole") as? String else {return nil}
self.init(key: aKey, email: anEmail, fKey: aFamilyKey, uName:userName, provider:aProvider, role: aRole)
}
private class func getCurrentUserURL() -> NSURL {
let documentsDirectory = NSFileManager().URLsForDirectory((.DocumentDirectory), inDomains: .UserDomainMask).first!
let userPath = documentsDirectory.URLByAppendingPathComponent("currentUser")
return userPath
}
class func saveCurrentUserToDisk(user:User){
let success = NSKeyedArchiver.archiveRootObject(user, toFile: User.getCurrentUserURL().path!)
if !success {
print("failed to save user to disk")
}
}
class func loadCurrentUserFromDisk() -> User?{
return NSKeyedUnarchiver.unarchiveObjectWithFile(User.getCurrentUserURL().path!) as? User
}
在我注册的 VC 中将用户存储到磁盘:
let newUser = User(key: authData.uid, email: self.emailField.text!, fKey: newFamily.key, uName: self.usernameField.text!, provider: authData.provider, role: "parent")
newUser.createUserRecords()
User.saveCurrentUserToDisk(newUser)
然后尝试访问数据:
if let user = User.loadCurrentUserFromDisk() {
print(user)
}
见下文编辑这会打印一个空行。我不知道该怎么做才能将此用户保存到磁盘。基于此尝试,尝试将其保存在用户默认值中似乎不是一个好主意,并且它作为单个用户的数据集如此之小,无论如何将数据对象存储在磁盘上都不会受到伤害。只需要弄清楚为什么我不能让它工作。我还尝试将所有实例变量从 let 更新为 var 并将 "" 分配为字符串值。我希望第二双眼睛可以帮助我看到我在这里缺少的东西。提前致谢!
编辑:当我将实例变量更改为 vars 并将它们的值设置为空字符串时,现在对象没有被返回,并且没有任何内容打印到控制台。如果我将它们改回来,那么即使我没有覆盖描述,用户也会向控制台打印一个空白行。如果我尝试打印实例变量,它也会再次打印一个空字符串。
所以我也决定检查位置。价值观都在那里。只是没有使用 NSKeyedUnarchiver 恢复它们。我打印了文件位置以验证它尝试访问正确的位置并且一切都很好。文档的 XML 在这里没有很好地显示。我是该网站的新手,我不相信我可以上传文件。但我查看了生成的 plist 及其所有内容。我离放弃这一点不远了,只是手动将数据存储到 plist 中。不确定与 NSKeyedArchiver 的好处和使用 NSCoding 相比会导致什么问题
【问题讨论】:
-
您说
print(user)打印一个空行,但除非您已覆盖description,否则您会希望它打印类名,而不是空字符串。 -
没错,因为我没有覆盖描述,所以我使用它只是为了测试对象是否正确返回。这也发生了一些变化,因为我将实例变量设置为 var 并且没有检索到对象。将更新我的问题以显示这一点。
-
值得注意的是,如果任何守卫在便利初始化程序中失败,您将退出初始化。使用
let aKey = aDecoder.decodeObjectForKey("userKey") as? String ?? ""之类的模式可能会更好。 -
那行得通。原来家庭钥匙有问题。家庭密钥被存储在生成的 plist 中......现在让我感觉很糟糕。我忘了我更新了键,所以它们不会与 Family 对象键冲突(而且我从未更新过这个线程)。我在它们前面加上了用户,除了在编码家庭密钥时它是正确的“userFamilyKey”,但在解码时我将密钥设置为“usersFamilyKey”。一个额外的字符打破了它。我不敢相信我从来没有注意到,一旦我看到这个对象就被保存了!非常感谢您的建议:-)
标签: ios xcode swift nscoding nskeyedunarchiver