Issue #334
NSSecureCoding has been around since iOS 6 and has had some API changes in iOS 12
A protocol that enables encoding and decoding in a manner that is robust against object substitution attacks.
https://developer.apple.com/documentation/foundation/nscoder/2292924-decodeobject
If the coder responds true to requiresSecureCoding, then the coder calls failWithError(_:) in either of the following cases: The class indicated by cls doesn’t implement NSSecureCoding. The unarchived class doesn’t match cls, nor do any of its superclasses.
If the coder doesn’t require secure coding, it ignores the cls parameter and does not check the decoded object.
The class must subclass from NSObject
and conform to NSSecureCoding
class Note: NSObject, NSSecureCoding {
static var supportsSecureCoding: Bool = true
func encode(with aCoder: NSCoder) {
aCoder.encode(id, forKey: "id")
aCoder.encode(text, forKey: "text")
aCoder.encode(date, forKey: "date")
}
required init?(coder aDecoder: NSCoder) {
guard
let id = aDecoder.decodeObject(of: [NSString.self], forKey: "id") as? String,
let text = aDecoder.decodeObject(of: [NSString.self], forKey: "text") as? String,
let date = aDecoder.decodeObject(of: [NSDate.self], forKey: "date") as? Date
else {
return nil
}
self.id = id
self.text = text
self.date = date
}
let id: String
var text = "untitled"
var date: Date = Date()
override init() {
id = UUID().uuidString
super.init()
}
}
First, we need to serialize to Data, then use EasyStash for easy persistency
do {
let securedItems = items.map({ SecuredClientLoggerItem(item: $0) })
if #available(iOS 11.0, *) {
let data = try NSKeyedArchiver.archivedData(
withRootObject: securedItems,
requiringSecureCoding: true
)
try data.write(to: fileUrl)
} else {
_ = NSKeyedArchiver.archiveRootObject(
securedItems,
toFile: fileUrl.path
)
}
} catch {
print(error)
}
Then we can use unarchiveTopLevelObjectWithData
to unarchive array
do {
let data = try Data(contentsOf: fileUrl)
let notes = try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data) as? [Note]
// notes is of type [Note]?
} catch {
print(error)
}
Note that for UUID, NSCoding seems to convert to UUID instead of String
let id = aDecoder.decodeObject(
of: [NSUUID.self],
forKey: "id"
) as? UUID,