I had a flash retreat recently

-[NSKeyedUnarchiver decodeObjectForKey:]: cannot decode object of class (AppName.ClassModel) for key (NS.objects) because no class named "AppName.ClassModel" was found; the class needs to be defined in source code or linked in from a library (ensure the class is part of the correct target). If the class was renamed, use setClassName:forClass: to add a class translation mapping to NSKeyedUnarchiver

The reason was that componentization moved a class from the main project to a component. The result is the problem above.

Why does moving a class do that?

The reason is that the old version of the code uses the NSKeyedUnarchiver class archive and uses a class ClassModel. If the new code changes the name or namespace of the class ClassModel, the problem will be reported that the class can not be found. Componentization is to move the class in the main project to the component, and the namespace is changed.

The solution is simple. Add one more line of code

NSKeyedUnarchiver.setClass(ClassModel.self, forClassName: "AppName.ClassModel")
Copy the code

Just rebind it to a new class.

But this is too bad, isn’t it common to change your name? And I looked online and some people changed the name of the main project causing similar problems.

The core is the namespace.

Is there a better way to deal with him. Difficulty can only be fixed during flash retreat? After all, a lot of times in development you don’t use old data to validate new code logic.

There is really no good way, after all, it is normal for your archived classes to be modified in code. Can we also remember the namespace of the class in advance when archiving, and inject it with a class by default, as a development specification?

Such as

NSKeyedUnarchiver.setClass(ClassModel.self, forClassName: "AppName.ClassModel")
let list = NSKeyedUnarchiver.unarchiveObject(withFile: payLogFilePath) as? [ClassModel]
Copy the code

But moving classes into components like this is also problematic. After all, the component name is not AppName

Finally came up with a way to do this

do {
    let list = try NSKeyedUnarchiver.unarchiveObject(withFile: payLogFilePath) as? [ClassModel]}catch {
	print("error")}Copy the code

But this is just not flash back, the emergence of the problem, or the same. And that would allow the problem to be swept under the carpet, as if there was a problem, but the technology developer didn’t know it.

And finally came up with this idea

do {
    let list = try NSKeyedUnarchiver.unarchiveObject(withFile: payLogFilePath) as? [ClassModel]}catch {
    // Avoid flashbacks and let Bugly collect errors
    Bugly.reportException(withCategory: 6,
    name: "Something went wrong.",
    reason: "NSKeyedUnarchiver had an error converting the model.",
    callStack: [],
    extraInfo: [:],
    terminateApp: false)}Copy the code

On the one hand, it avoids flash rollback. On the other hand, Bugly and other logging platforms can also receive error messages. It is convenient for rectification when problems arise.

Seems to have a development of the specification, when using NSKeyedUnarchiver. UnarchiveObject, you should use the above try encase, and upload error log.