NSKeyedArchiving issue

I have a large code that I try to update to change deprecated APIs.

In the former version, I used forWritingWith and forReadingWith

    let data = NSMutableData()
    let archiver = NSKeyedArchiver(forWritingWith: data)
    archiver.encode(myObject, forKey: theKey)
if let data = NSMutableData(contentsOf: anURL) {
  let unarchiver = NSKeyedUnarchiver(forReadingWith: data as Data)
        let myObject = unarchiver.decodeObject(forKey: theKey) as! TheObjectType // <<-- returns the object

That I changed to

    let data = NSMutableData()
    let archiver = NSKeyedArchiver(requiringSecureCoding: true)
    archiver.encode(myObject, forKey: theKey)
 if let data = NSMutableData(contentsOf: anURL) {
        do {
            let unarchiver = try NSKeyedUnarchiver(forReadingFrom: data as Data)
           let myObject = unarchiver.decodeObject(forKey: theKey) as? TheObjectType // <<-- This returns nil

This builds correctly.

But on execution, unarchiver.decodeObject now returns nil.

I have searched extensively to find the cause to no avail.

I may probably change the design to avoid NSKeyedArchiver, but that would be a huge refactoring.

I probably miss something obvious.

Could someone hint at the possible cause ?

Answered by DTS Engineer in 873204022

Hey Claude31, it’s nice for me to be helping you for a change (-:

It’s hard to tell exactly what’s going wrong here without know more about the objects in play. However, in general, when you decode something from a secure keyed archive, you have to tell the system what type you’re expecting. That’s the key factor is what makes it secure.

Over the years I’ve helped a bunch of folks with problems like this. All of these threads have code snippets from me that you should find useful:

If you’re still stuck, distill your problem into a test case that I can run, reply here with that, and I’ll take a deeper look.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Hey Claude31, it’s nice for me to be helping you for a change (-:

It’s hard to tell exactly what’s going wrong here without know more about the objects in play. However, in general, when you decode something from a secure keyed archive, you have to tell the system what type you’re expecting. That’s the key factor is what makes it secure.

Over the years I’ve helped a bunch of folks with problems like this. All of these threads have code snippets from me that you should find useful:

If you’re still stuck, distill your problem into a test case that I can run, reply here with that, and I’ll take a deeper look.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Hey Quinn, thanks for all the material.

I realize that I have a basic issue in my code.

data is not loaded.

In the previous version, archiver had a connection to data

let archiver = NSKeyedArchiver(forWritingWith: data)

That's no more the case, so data is empty, hence the problems.

    let data = NSMutableData()
    let archiver = NSKeyedArchiver(requiringSecureCoding: true)
    archiver.encode(myObject, forKey: theKey)
    archiver.encode(myObject2, forKey: theKey2)
    archiver.finishEncoding()
    do {
        try data.write(to: an uRL, options: []) // data is empty of course !
    } catch {
     }

So should I replace:

    archiver.encode(myObject, forKey: theKey)
    archiver.encode(myObject2, forKey: theKey2)
    archiver.finishEncoding()
    do {
        try data.write(to: anURL, options: []) // So object and object2 are on file

with

    let data = try! NSKeyedArchiver.archivedData(withRootObject: myObject, requiringSecureCoding: true)
    let data2 = try! NSKeyedArchiver.archivedData(withRootObject: myObject2, requiringSecureCoding: true)
    archiver.finishEncoding()

If so, how do I write object and object2 in a single file properly ? Would I have to include all in a single root class ?

Also, when I compare to https://developer.apple.com/forums/thread/759746,

my required init(coder decoder: NSCoder) is different.

   required init(coder decoder: NSCoder) {
        
        super.init() 
        var1 = decoder.decodeObject(forKey: key) as? [someType]
        var2 = decoder.decodeObject(forKey: key2) as? [someType2]
    }

I do not use decodeObject(of:) as in the reference

            let identifier = decoder.decodeObject(of: NSString.self, forKey: "identifier"),
            let codeDataModels = decoder.decodeArrayOfObjects(ofClass: CodeDataModel.self, forKey: "codeDataModels")

Is it OK ?

NSKeyedArchiving issue
 
 
Q