Я работаю над проектом, где мне нужно записать некоторые объекты на диск, а затем вернуть их позже. Я использовал NSKeyedArchiver
и NSKeyedUnarchiver
, чтобы сделать запись и чтение, убедившись, что мои пользовательские классы соответствуют NSCoding
. Он не работал, и поэтому, после долгого времени отладки и поиска в Интернете, я решил изолировать проблему.Почему NSKeyedArchiver и NSKeyedUnarchiver работают так, как ожидалось?
Может кто-нибудь рассказать мне, почему этот код не делает то, что я ожидаю от него? Это, вероятно, очевидно, но, глядя на него в течение многих часов, я все еще не могу разобраться.
У меня есть контроллер представления, определенный в 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
}
Я неверно истолковал «Обернуть ваши данные в классе»?
Вы прошли через отладчик? – Paulw11
Да. Кажется, что запись данных успешно (без исключения), но когда я перестраиваю и запускаю приложение, строка 'loadedMessage' имеет« неспособную прочитать данные », написанную рядом с ней в средстве просмотра локальных переменных. Исходя из этого, я думаю, что существует либо проблема с тем, как данные записываются (чтобы их нельзя было прочитать позже), либо просто возникает проблема с ее чтением. – xander
Теперь я установил 'filePath' в' URL (fileURLWithPath: «/ Users/Xander/Desktop») .appendingPathComponent («message») ', чтобы узнать, что произойдет, если я попытаюсь написать прямо на мой рабочий стол. Он работает, и файл, как представляется, содержит данные. Все еще не удалось его разблокировать, хотя ... – xander