【发布时间】:2017-02-05 11:40:22
【问题描述】:
我一直在做一个项目,我需要将一些对象写入磁盘,然后稍后再将它们取回。我使用NSKeyedArchiver 和NSKeyedUnarchiver 进行写入和读取,确保我的自定义类符合NSCoding。它没有工作,因此,经过很长时间尝试调试它并搜索网络后,我决定隔离问题。
有人能告诉我为什么这段代码没有按照我的预期做吗?这可能是显而易见的,但盯着它看了好几个小时后,我仍然无法解决。
我在Main.storyboard 中定义了一个视图控制器,其中包含UILabel、UITextField 和UIButton。这个想法是用户可以输入一些内容,按下“发布”按钮,标签将显示他们输入的内容。每次用户输入内容时,我都希望将其写入磁盘,以便在退出应用程序并再次加载视图时,将返回消息并通过标签显示。
目前,标签显示用户输入的内容,但如果我退出应用并重新打开它,标签只会显示“您在此处的消息”,这是我在情节提要中分配给它的字符串。
我感觉这可能与unarchiveObject(withFile:) 调用和/或对String 的类型转换有关,因为我在某处读到,从 Swift 3 开始,值类型必须使用它们自己的方法(例如unarchiveBool(withFile:)),尽管String 似乎没有这种方法。
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var outputLabel: UILabel!
@IBOutlet weak var textBox: UITextField!
var filePath: URL!
override func viewDidLoad() {
super.viewDidLoad()
filePath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0].appendingPathComponent("message")
// Load message
if let loadedMessage = NSKeyedUnarchiver.unarchiveObject(withFile: filePath.absoluteString) as? String {
outputLabel.text = loadedMessage
}
}
@IBAction func textFieldDoneEditing(_ sender: UITextField) {
sender.resignFirstResponder()
}
@IBAction func postButtonTapped(_ sender: Any) {
outputLabel.text = textBox.text
textBox.text = ""
let str = outputLabel.text!
// Save message
let data = NSKeyedArchiver.archivedData(withRootObject: str)
do {
try data.write(to: filePath)
} catch {
print("Couldn't write file.")
}
}
}
好的,@gkchristopher 指出NSCoder 不能直接与String 一起工作,所以我应该将我的数据包装在一个符合NSCoding 的类中。所以这是一个尝试这样做的小类:
class DataThing: NSObject, NSCoding {
var message: String!
init(withMessage message: String) {
self.message = message
}
required convenience init?(coder aDecoder: NSCoder) {
self.init(withMessage: aDecoder.decodeObject(forKey: "message") as! String)
}
func encode(with aCoder: NSCoder) {
aCoder.encode(message, forKey: "message")
}
}
我可以用这个类很好地写数据:
let dataThing = DataThing(withMessage: str)
// Save message
let data = NSKeyedArchiver.archivedData(withRootObject: dataThing)
do {
try data.write(to: filePath)
} catch {
print("couldn't write file.")
}
但是,阅读仍然不起作用:
if let loadedData = NSKeyedUnarchiver.unarchiveObject(withFile: filePath.absoluteString) as? DataThing {
outputLabel.text = loadedData.message
}
我是否误解了“将您的数据包装在一个类中”?
【问题讨论】:
-
你有调试过吗?
-
是的。它似乎成功地写出了数据(没有抛出异常),但是当我重建并运行应用程序时,
loadedMessage字符串在局部变量查看器中旁边写着“无法读取数据”。基于此,我认为要么是写入数据的方式有问题(导致以后无法读取),要么只是读取有问题。 -
我现在将
filePath设置为URL(fileURLWithPath: "/Users/Xander/Desktop") .appendingPathComponent("message"),看看如果我尝试直接写到我的桌面会发生什么。它可以工作,并且该文件似乎包含数据。但是仍然无法取消存档... -
您实际上并不需要创建自己的数据类型。直接读写数据即可。
标签: ios swift nskeyedarchiver