问题
I looked through whole SO but still no answer. My app reports this problem:
Fatal Exception: NSInvalidUnarchiveOperationException *** -[NSKeyedUnarchiver decodeObjectForKey:]: cannot decode object of class (App_Title.Products) for key (NS.objects); the class may be defined in source code or a library that is not linked
I did already do NSKeyedUnarchiver.setClass just before #unarchiveObject:
func loadProducts() -> [Products]? {
NSKeyedUnarchiver.setClass(Products.self, forClassName: "Products")
let unarchivedData = NSKeyedUnarchiver.unarchiveObject(withFile: Products.ArchiveURL.path)
My Products class begins with @Objc:
import Foundation
@objc(Products)
class Products: NSObject, Codable, NSCoding { ... }
Adding the two lines above which seemed to help people didn't bring me any luck. Before them and after them it's the same behaviour. I personally could never reproduce this issue myself.
During development I keep very closely to the app guide on peristance and reviewed it multiple times.
Just before NSKeyedArchiver I check for file existance:
let filePath = Products.ArchiveURL.path
let fileManager = FileManager.default
if fileManager.fileExists(atPath: filePath) {
Here some additional informations in screenshots.
The only place where I could find a real exception description was Firebase Crashalytics:
A screenshot from the Xcode Organizer under the Crash tab:
Which leads to this line in the code:
NSKeyedUnarchiver.setClass(Products.self, forClassName: "Products")
let unarchivedData = NSKeyedUnarchiver.unarchiveObject(withFile: Products.ArchiveURL.path)
Products class with @Objc annotation.
回答1:
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.
来源:https://stackoverflow.com/questions/57877912/nskeyedunarchiver-decodeobjectforkey-cannot-decode-object-of-class-for-key-ns