私はいくつかのオブジェクトをディスクに書き込んだ後、後でそれらを再び取得する必要があるプロジェクトに取り組んできました。私はNSKeyedArchiver
とNSKeyedUnarchiver
を使って書き込みと読み取りを行い、私のカスタムクラスがNSCoding
に適合していることを確認しました。それは動作していなかったので、それをデバッグしてWebを検索しようとした後、私は問題を切り分けることに決めました。NSKeyedArchiverとNSKeyedUnarchiverがここで期待どおりに動作しないのはなぜですか?
誰かがこのコードが私が期待することをしない理由を教えてください。それはおそらく明らかですが、何時間もそれを見つめた後、私はまだそれを解決することはできません。
私は、UILabel
、UITextField
およびUIButton
のMain.storyboard
で定義されたビューコントローラを持っています。ユーザーは何かを入力して「投稿」ボタンを押すと、入力した内容がラベルに表示されます。ユーザーが何かを入力するたびに、ディスクに書き込むようにして、アプリケーションを終了してビューを再度読み込むと、メッセージが戻ってラベルに表示されるようにします。
現在のところ、ラベルにはユーザーが入力した内容が表示されますが、アプリを終了してもう一度開くと、ラベルにはストーリーボードに割り当てられた文字列の「Your message here」と表示されます。
私は、私はスウィフト3以降、値の型は、独自の方法(例えばunarchiveBool(withFile:)
)を使用して、アーカイブされていないされなければならないことをどこかで読んので、String
にunarchiveObject(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
はので、私はNSCoding
に準拠したクラスで私のデータをラップする必要がありString
を直接操作することができないことを指摘しています。そこでここではそれを行うにしようと小さなクラスだ:
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
}
私は「クラスでデータをラップする」と誤解しましたか? filePath.path
に
変更filePath.absoluteString
:
デバッガを使用しましたか? – Paulw11
はい。データを正常に出力しているようですが(例外はスローされません)、アプリケーションを再構築して実行すると、ローカル変数ビューアの隣に 'loadedMessage'文字列に 'データを読み取れません'という文字列があります。それに基づいて、私は、データが書き込まれる方法(後で読むことができないような)に問題があるか、または単にそれを読むことに問題があると思います。 – xander
ファイルパスを 'URL(fileURLWithPath:"/Users/Xander/Desktop ").appendingPathComponent(" message ")'に設定しました。それは動作し、ファイルにはデータが含まれているように見えます。しかしまだそれを解凍することに失敗しました... – xander