Bingo - found the problem. I broke out the archiving code that was not working and put it in a new simple app (see below). I created a simple class with a Swift Array in it, wrote the archive out with the non NSSecureCoding code. Then changed the code so the class uses NSSecureCoding and changed the de-archiving code to read that file back in using:
try newTest = NSKeyedUnarchiver.unarchivedObject(ofClasses: [Test.self], from: fileData as Data) as? Test
It failed silently like the main app failed. Then as suggested by Polyphonic I added NSArray.self to the ofClasses: parameter - ran the app again and a litany of good info was spewed to the console when the test app tried to decode the Array - the real app did not send anything to the console - it just failed silently returning a nil for the Array. Here's the console message:
NSCoderTest[11222:509325] [general] *** -[NSKeyedUnarchiver validateAllowedClass:forKey:] allowed unarchiving safe plist type ''NSNumber' (0x2140200a8) [/System/Library/Frameworks/Foundation.framework]' for key 'NS.objects', even though it was not explicitly included in the client allowed classes set: '{(
"'NSCoderTest.Test' (0x100eb0700) , "'NSArray' (0x213ff2440) [/System/Library/Frameworks/CoreFoundation.framework]"
)}'. This will be disallowed in the future.
Then I added NSNumber.self to the ofClasses: parameter and all works as it should. The main app where the code was failing was created three years ago with whatever was the current Xcode version at the time. I suspect there is something mangled in the project file that keeps it from emitting some error / warning messages to the console. Great.
The laconic documentation for unarchivedObject(ofClasses:from:) says "A set of classes, at least one of which the root object should conform to". I think that means to add every class that your class needs to de-archive. Polyphonic has an excellent explanation about why this is necessary in his reply above.
Polyphonic - thanks so much for the nudge in the right direction.
Hey Apple, maybe a little more work on the documentation and a little less work on emojis maybe?
Simple test code -
class Test: NSObject, NSSecureCoding {
static var supportsSecureCoding: Bool = true
var i: Int64 = 55
var theArray: Array<Bool>? = [true, true, true, true]
func encode(with coder: NSCoder) {
coder.encode(i, forKey: "var_i")
coder.encode(theArray, forKey: "var_a")
}
override init() { }
required init?(coder: NSCoder) {
if (coder.containsValue(forKey: "var_i")) {
i = coder.decodeInt64(forKey: "var_i")
}
if (coder.containsValue(forKey: "var_a")) {
theArray = coder.decodeObject(forKey: "var_a") as? Array<Bool>
}
}
}
func applicationDidFinishLaunching(_ aNotification: Notification) {
var newTest: Test?
let fileURL = URL(fileURLWithPath: "/Users/username/Downloads/testData", isDirectory: false)
//let t1 = Test()
//t1.i = 100
//t1.a[1] = false
//t1.a[2] = false
do {
// let theData = try NSKeyedArchiver.archivedData(withRootObject: t1, requiringSecureCoding: false)
// try theData.write(to: fileURL, options: NSData.WritingOptions.atomic)
let fileData = try NSData(contentsOf: fileURL, options: [])
// try newTest = NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(fileData as Data) as? Test
try newTest = NSKeyedUnarchiver.unarchivedObject( ofClasses: [Test.self, NSArray.self],
from: fileData as Data) as? Test
}
catch {
print("well that didn't work.")
}
}