Cannot Decode Object of Class

Cannot decode object of class

NOTE: While the information in this answer is correct, the way better answer is the one below by @agy.

This is caused by the compiler creating MyApp.Person & MyAppWatchKitExtension.Person from the same class. It's usually caused by sharing the same class across two targets instead of creating a framework to share it.

Two fixes:

The proper fix is to extract Person into a framework. Both the main app & watchkit extension should use the framework and will be using the same *.Person class.

The workaround is to serialize your class into a Foundation object (like NSDictionary) before you save & pass it. The NSDictionary will be code & decodable across both the app and extension. A good way to do this is to implement the RawRepresentable protocol on Person instead.

NSKeyedUnarchiver decodeObjectForKey:]: cannot decode object of class

What you're getting here is an exception; exceptions cannot be caught or handled in Swift, and are different from errors, which is why you can't wrap the call in a do {} catch {}.

The issue here is that your archive contains the name of a class which is then not available at runtime, which can happen for several reasons:

  1. You encoded the archive in an app that contains the class, and are attempting to decode in a different app which does not contain the class. This can happen if you forget to link the class implementation with the target you're working with, but this is much less likely in Swift because you can't import the header and forget to link the implementation
  2. The class name has changed. This can happen for a few reasons itself, but in Swift, the most likely reason is due to your app/module name changing. Classes in Swift have runtime names which include the full path to the class. If you've got an app named "MyApp", a class called "Foo" has a qualified name of "MyApp.Foo". Similarly, a class "Bar" nested in "Foo" would have a qualified name of "MyApp.Foo.Bar". Importantly, if you change the name of your app (which is the name of your main module), the name of the class changes!

What's likely happening here is that you've either renamed the target since the archive was written (which would change the class name), or you wrote the archive with the class in one target, but are decoding in another. Even though you include the same class in both, they have different names ("MyTarget1.UserSession" vs. "MyTarget2.UserSession").

You can remedy this with a few steps:

  1. Give the class a stable name which won't change with @objc, e.g. @objc(UserSession) class UserSession { ... }. This will give the class an Objective-C name that is constant and does not depend on the module name in any way
  2. Use NSKeyedUnarchiver.setClass(_:forClassName:) to migrate the old archives to use the new, stable class

See NSKeyedArchiver and sharing a custom class between targets for the full details on how to migrate the archive forward.

NSKeyedUnarchiver decodeObjectForKey:]: cannot decode object of class

What you're getting here is an exception; exceptions cannot be caught or handled in Swift, and are different from errors, which is why you can't wrap the call in a do {} catch {}.

The issue here is that your archive contains the name of a class which is then not available at runtime, which can happen for several reasons:

  1. You encoded the archive in an app that contains the class, and are attempting to decode in a different app which does not contain the class. This can happen if you forget to link the class implementation with the target you're working with, but this is much less likely in Swift because you can't import the header and forget to link the implementation
  2. The class name has changed. This can happen for a few reasons itself, but in Swift, the most likely reason is due to your app/module name changing. Classes in Swift have runtime names which include the full path to the class. If you've got an app named "MyApp", a class called "Foo" has a qualified name of "MyApp.Foo". Similarly, a class "Bar" nested in "Foo" would have a qualified name of "MyApp.Foo.Bar". Importantly, if you change the name of your app (which is the name of your main module), the name of the class changes!

What's likely happening here is that you've either renamed the target since the archive was written (which would change the class name), or you wrote the archive with the class in one target, but are decoding in another. Even though you include the same class in both, they have different names ("MyTarget1.UserSession" vs. "MyTarget2.UserSession").

You can remedy this with a few steps:

  1. Give the class a stable name which won't change with @objc, e.g. @objc(UserSession) class UserSession { ... }. This will give the class an Objective-C name that is constant and does not depend on the module name in any way
  2. Use NSKeyedUnarchiver.setClass(_:forClassName:) to migrate the old archives to use the new, stable class

See NSKeyedArchiver and sharing a custom class between targets for the full details on how to migrate the archive forward.

NSKeyedUnarchiver decodeObjectForKey: cannot decode object of class for key (NS.objects)

It seems that you are mixing up Codable and NSCoding. Don't try to use both simultaneously. NSKeyedUnarchiver belongs to NSCoding.

Your class contains property list compliant properties. Drop NSCoding and use only Codable. (By the way it's recommended to name the class in singular form Product).

Delete everything which is related to NSCoding including the protocol conformance and with Codable it's not necessary that the class must inherit from NSObject (the object can be even a struct).

The loadProducts function can be reduced to

func loadProducts() throws -> [Product] {
let data = try Data(contentsOf: Product.ArchiveURL)
return try PropertyListDecoder().decode([Product].self, from: data)
}

It's good practice to hand over thrown errors to the caller

And delete the CodingKeys, you don't need them if the keys match the property names.

NSKeyedUnarchiver decodeObjectForKey: cannot decode object of class AMPathPopUpButton for key NS.objects

To satisfy this error and get your popup's UI elements building/showing takes two simple steps:

  1. Add the "Automator.framework" in your project's "General" setting page. See this answer here: https://stackoverflow.com/a/25667439/1762493
  2. Then be sure to link the elements in your popup to an @IBOutlet variable like so: @IBOutlet var imgPath: NSPathCell!. Once you add the @IBOutlet var you have to drag your mouse and connect it to the UI element. You'll need an @IBOutlet or @IBAction for each element you drew in the Main.storyboard like so:

Xcode screenshot dragging IBOutlet variable to Main.storyboard UI element

There's a good tutorial at RayWenderlich.com for creating a popup and adding UI elements connected to Main.storyboard for MacOS apps here:

https://www.raywenderlich.com/450-menus-and-popovers-in-menu-bar-apps-for-macos

-[NSKeyedUnarchiver decodeObjectForKey:]: cannot decode object of class

I found the reason for the above.

Basically I changed the project target name from version 1 to version 2. So it was trying to decode ProjectName2.ProjectFile instead of ProjectName.ProjectFile.

The possible way to avoid is @objc(PFUserUtils) for the class when you start the first version. If you change the target name like me, use NSKeyedUnarchiver.setClass(className forClassName:name) method to set the class name to old one.

NSKeyedUnarchiver cannot decode object of class NSKnownKeysDictionary1

I asked this on the Apple Developer forums and (for once) got a good answer from Apple Developer Relations. I'll quote the important bits:

NSKnownKeysDictionary1 is a Core Data voodoo that I do not understand.
... Clearly something is going wrong with its serialisation and
deserialisation. Do you have Core Data up and running on both ends of
the wormhole? Regardless, it might make more sense to do a deep copy
of your bookmarks array (and anything else you get back from Core
Data) so that you’re sending standard dictionaries across the ‘wire’
rather than Core Data stuff.

So my solution is either to add the Core Data framework to the extension or to do the deep copy. (I've temporarily done the former. The proper solution is probably the latter.)

-[NSKeyedUnarchiver decodeObjectForKey:]: cannot decode object of class (myCustomClass)

Finally solved, I delete everything from the cache as I could not find following path:

/Users/USER/Library/Caches/*/DocumentBasedApp.app/Contents/MacOS/DocumentBasedApp

and it started working! Bizarre!



Related Topics



Leave a reply



Submit