我是斯威夫特的新手,请帮忙。
尝试存档和取消存档对象并在磁盘上写入/读取它。
我有四行
class FourLines: NSObject, NSCoding, NSSecureCoding, NSCopying {
static var supportsSecureCoding: Bool{
return true
}
private static let linesKey = "linesKey"
var lines: [String]?
override init() {
}
required init?(coder aDecoder: NSCoder) {
print("FourLines init")
lines = aDecoder.decodeObject(forKey: FourLines.linesKey) as? [String]
}
func encode(with aCoder: NSCoder) {
print("FourLines encode")
if let saveLines = lines {
aCoder.encode(saveLines, forKey: FourLines.linesKey)
}
}
func copy(with zone: NSZone? = nil) -> Any {
print("copy with zone")
let copy = FourLines()
if let linesToCopy = lines {
var newLines = Array<String>()
for line in linesToCopy {
newLines.append(line)
}
copy.lines = newLines
}
return copy
}
}
在ViewController中,我尝试保存和读取数据:
class ViewController: UIViewController {
private static let linesKey = "linesKey"
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let fileURL = self.dataFileUrl()
if FileManager.default.fileExists(atPath: fileURL.path!) {
let codedData = try! Data(contentsOf: fileURL as URL)
print(codedData)
let unarchiver = try! NSKeyedUnarchiver(forReadingFrom: codedData)
if unarchiver.containsValue(forKey: ViewController.linesKey) {
print("viewDidLoad contains value")
} else {
print("viewDidLoad doesn't conains value")
}
let fourLines = unarchiver.decodeObject(forKey: ViewController.linesKey) as! FourLines?
print(fourLines?.lines?.count)
}
let app = UIApplication.shared
NotificationCenter.default.addObserver(self, selector: #selector(self.applicationWillResignActive(notification:)), name: UIApplication.willResignActiveNotification, object: app)
}
@objc func applicationWillResignActive(notification: NSNotification) {
print("applicationWillResignActive")
let fileURL = self.dataFileUrl()
print(fileURL)
let fourLines = FourLines()
let array = (self.lineFields as NSArray).value(forKey: "text") as! [String]
fourLines.lines = array
let archiver = NSKeyedArchiver(requiringSecureCoding: true)
archiver.encode(fourLines, forKey: ViewController.linesKey)
let data = archiver.encodedData
do {
try data.write(to: fileURL as URL)
} catch {
print("Error is \(error)")
}
}
@IBOutlet var lineFields: [UITextField]!
func dataFileUrl() -> NSURL {
let urls = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
var url: NSURL?
url = URL(fileURLWithPath: "") as NSURL
do {
try url = urls.first!.appendingPathComponent("data.archive") as NSURL
} catch {
print("Error is \(error)")
}
return url!
}
}
当我辞职时,app encode方法调用:
四行编码
当我尝试加载它时,我看到文件被创建并且包含值,但是在解码fourLines对象时,我总是有nil:
322字节
viewDidLoad包含值
无
还有init?编码器和带区域复制的编码器从不调用。
我做错什么了?
最佳答案
你的问题是你从未初始化你的行数组。将其声明更改为非可选,并使用空数组对其进行初始化。这样试试:
class FourLines: NSObject, NSCoding, NSSecureCoding, NSCopying {
static var supportsSecureCoding: Bool { return true }
private static let linesKey = "linesKey"
var lines: [String] = []
override init() { }
required init?(coder aDecoder: NSCoder) {
print(#function)
lines = aDecoder.decodeObject(forKey: FourLines.linesKey) as? [String] ?? []
}
func encode(with aCoder: NSCoder) {
print(#function)
aCoder.encode(lines, forKey: FourLines.linesKey)
}
func copy(with zone: NSZone? = nil) -> Any {
print(#function)
let copy = FourLines()
var newLines = Array<String>()
for line in lines {
newLines.append(line)
}
copy.lines = newLines
return copy
}
}
操场测试:
let fourLines = FourLines()
fourLines.lines = ["line1","line2","line3","line4"]
let data = try! NSKeyedArchiver.archivedData(withRootObject: fourLines, requiringSecureCoding: true)
let decodedFourlInes = try! NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data) as! FourLines
decodedFourlInes.lines // ["line1", "line2", "line3", "line4"]
顺便说一下,如果您试图持久化文本字段值,那么ViewController应该如下所示:
class ViewController: UIViewController {
@IBOutlet var lineFields: [UITextField]!
private static let dataFileUrl = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!.appendingPathComponent("lines.plist")
override func viewDidLoad() {
super.viewDidLoad()
do {
let lines = (try NSKeyedUnarchiver
.unarchiveTopLevelObjectWithData(Data(contentsOf: ViewController.dataFileUrl)) as! FourLines)
.lines
var index = 0
lineFields.forEach {
$0.addTarget(self, action: #selector(editingDidEnd), for: .editingDidEnd)
$0.text = lines[index]
index += 1
}
} catch {
print(error)
}
}
@objc func editingDidEnd(_ textField: UITextField) {
print(#function)
let fourLines = FourLines()
fourLines.lines = lineFields.map { $0.text! }
do {
try NSKeyedArchiver
.archivedData(withRootObject: fourLines, requiringSecureCoding: true)
.write(to: ViewController.dataFileUrl)
} catch {
print(error)
}
}
}
关于ios - NSCoding encodeObject总是为零,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/57515385/