为什么 `NSKeyedUnarchiver` 无法解码 `Date`
Why `NSKeyedUnarchiver` is unable to decode for `Date`
最近,我正在处理 iOS 与 NSKeyedArchiver
和 NSKeyedUnarchiver
上的持久性问题。但是我遇到了一些问题。
代码如下:
import Foundation
class Model {
static let instance = Model()
static let DocumentsDirectory = FileManager().urls(for: .documentDirectory, in: .userDomainMask).first!
static let TestArchiveURL = DocumentsDirectory.appendingPathComponent("t")
static func getInstance() -> Model {
return instance
}
var str = "String"
var date = Date()
func save() {
let coder = NSKeyedArchiver(requiringSecureCoding: false)
coder.encode(str, forKey: ModelPropertyKey.str)
coder.encode(date, forKey: ModelPropertyKey.date)
do {
try coder.encodedData.write(to: Model.TestArchiveURL)
} catch {
print("error write to file: " + error.localizedDescription)
}
do {
let data = try Data(contentsOf: Model.TestArchiveURL)
let decoder = try NSKeyedUnarchiver(forReadingFrom: data)
let strGot = decoder.decodeObject(forKey: ModelPropertyKey.str) as? String
let dateGot = decoder.decodeObject(forKey: ModelPropertyKey.date) as? Date
print("\(String(describing: strGot)) \(String(describing: dateGot))")
} catch {
print("Error read from file")
}
}
}
我用 encode(:forKey:)
编码数据并用 encodedData.write(to:)
获得持久性。然后我尝试使用 NSKeyedUnarchiver(forReadingFrom:)
和 decodeObject(forKey:)
从磁盘读取数据。但此策略适用于 String
而适用于 Date
。 print
输出:
Optional("String") nil
我想知道为什么会这样。
您需要指定要解码的对象类型,并且由于您正在解码 Date
对象,因此您需要了解 NSKeyedArchiver
和 NSKeyedUnarchiver
将桥接您的 Date
Swift 对象到 NSDate
Objective-C 对象以实现 swift 和 obj-c 之间的兼容性,因为 NSKeyedArchiver
使用 NSCoding
和 Date
不符合NSCoding
要做到这一点,请将解码更改为这样
let dateGot = decoder.decodeObject(of: NSDate.self, forKey: ModelPropertyKey.date)! as Date
但是我建议您使用 swift Codable
协议与 JSONEncoder
和 JSONDecoder
他们有一个非常好的 dateDecodingStrategy
允许指定您在编码和解码时的自定义日期格式化程序,它们还支持直接解码 Date
对象而无需桥接到 obj-c NSDate
当您尝试将对象作为 json 有效负载或解码时这很好它来自网络呼叫
这里有一个例子
let encoder = JSONEncoder()
let formatter = DateFormatter()
formatter.dateStyle = .full
formatter.timeStyle = .short
encoder.dateEncodingStrategy = .formatted(formatter)
let data = try? encoder.encode(Date())
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .formatted(formatter)
let newDate = try? decoder.decode(Date.self, from: data!)
最近,我正在处理 iOS 与 NSKeyedArchiver
和 NSKeyedUnarchiver
上的持久性问题。但是我遇到了一些问题。
代码如下:
import Foundation
class Model {
static let instance = Model()
static let DocumentsDirectory = FileManager().urls(for: .documentDirectory, in: .userDomainMask).first!
static let TestArchiveURL = DocumentsDirectory.appendingPathComponent("t")
static func getInstance() -> Model {
return instance
}
var str = "String"
var date = Date()
func save() {
let coder = NSKeyedArchiver(requiringSecureCoding: false)
coder.encode(str, forKey: ModelPropertyKey.str)
coder.encode(date, forKey: ModelPropertyKey.date)
do {
try coder.encodedData.write(to: Model.TestArchiveURL)
} catch {
print("error write to file: " + error.localizedDescription)
}
do {
let data = try Data(contentsOf: Model.TestArchiveURL)
let decoder = try NSKeyedUnarchiver(forReadingFrom: data)
let strGot = decoder.decodeObject(forKey: ModelPropertyKey.str) as? String
let dateGot = decoder.decodeObject(forKey: ModelPropertyKey.date) as? Date
print("\(String(describing: strGot)) \(String(describing: dateGot))")
} catch {
print("Error read from file")
}
}
}
我用 encode(:forKey:)
编码数据并用 encodedData.write(to:)
获得持久性。然后我尝试使用 NSKeyedUnarchiver(forReadingFrom:)
和 decodeObject(forKey:)
从磁盘读取数据。但此策略适用于 String
而适用于 Date
。 print
输出:
Optional("String") nil
我想知道为什么会这样。
您需要指定要解码的对象类型,并且由于您正在解码 Date
对象,因此您需要了解 NSKeyedArchiver
和 NSKeyedUnarchiver
将桥接您的 Date
Swift 对象到 NSDate
Objective-C 对象以实现 swift 和 obj-c 之间的兼容性,因为 NSKeyedArchiver
使用 NSCoding
和 Date
不符合NSCoding
要做到这一点,请将解码更改为这样
let dateGot = decoder.decodeObject(of: NSDate.self, forKey: ModelPropertyKey.date)! as Date
但是我建议您使用 swift Codable
协议与 JSONEncoder
和 JSONDecoder
他们有一个非常好的 dateDecodingStrategy
允许指定您在编码和解码时的自定义日期格式化程序,它们还支持直接解码 Date
对象而无需桥接到 obj-c NSDate
当您尝试将对象作为 json 有效负载或解码时这很好它来自网络呼叫
这里有一个例子
let encoder = JSONEncoder()
let formatter = DateFormatter()
formatter.dateStyle = .full
formatter.timeStyle = .short
encoder.dateEncodingStrategy = .formatted(formatter)
let data = try? encoder.encode(Date())
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .formatted(formatter)
let newDate = try? decoder.decode(Date.self, from: data!)