How to NSKeyedUnarchiver.unarchiveObject
The usage of the new API to archive an array is a bit tricky.
You could have figured it out yourself if you wouldn't ignore the errors with try?
/p>
To be able to decode an array of a custom class with unarchivedObject(ofClass:from:
you have to use the plural form unarchivedObject(ofClasses:from:
and specify both NSArray
(!) and the custom class. Further your class must adopt NSSecureCoding
class Record : NSObject, NSSecureCoding {
static var supportsSecureCoding: Bool {
return true
}
....
do {
let archived = try NSKeyedArchiver.archivedData(withRootObject: [defaultRecord], requiringSecureCoding: false)
let records = try NSKeyedUnarchiver.unarchivedObject(ofClasses: [NSArray.self, Record.self], from: archived) as! [Record]
print(records)
} catch { print(error) }
But why do you archive defaultRecord
as array at all? If you archive the single object you can leave your class as it is and write
do {
let archived = try NSKeyedArchiver.archivedData(withRootObject: defaultRecord, requiringSecureCoding: false)
let record = try NSKeyedUnarchiver.unarchivedObject(ofClass: Record.self, from: archived)
let records = [record]
print(records)
} catch { print(error) }
Side note: Consider to serialize the class with Codable
. It's swiftier and doesn't require inheritance from NSObject
.
How to deal with deprecated function 'unarchiveObject(with:)'?
You can do this in following way...
let result = jsonDict["result"] as? NSDictionary ?? [:]
let data = try! NSKeyedArchiver.archivedData(withRootObject: result, requiringSecureCoding: false)
UserDefaults.standard.set(data, forKey: "currentUser")
// Get data from Userdefault
let result = UserDefaults.standard.data(forKey: "currentUser")
if result != nil{
let dict = try! NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(result!) as? NSDictionary ?? [:]
print("Current User Details : - \(dict)")
}
Unarchive Array with NSKeyedUnarchiver unarchivedObject(ofClass:from:)
You can use unarchiveTopLevelObjectWithData(_:)
to unarchive the data archived by archivedData(withRootObject:requiringSecureCoding:)
. (I believe this is not deprecated yet.)
But before showing some code, you should better:
Avoid using
NSData
, useData
insteadAvoid using
try?
which disposes error info useful for debuggingRemove all unneeded casts
Try this:
private static func archiveWidgetDataArray(widgetDataArray : [WidgetData]) -> Data {
do {
let data = try NSKeyedArchiver.archivedData(withRootObject: widgetDataArray, requiringSecureCoding: false)
return data
} catch {
fatalError("Can't encode data: \(error)")
}
}
static func loadWidgetDataArray() -> [WidgetData]? {
guard
isKeyPresentInUserDefaults(key: USER_DEFAULTS_KEY_WIDGET_DATA), //<- Do you really need this line?
let unarchivedObject = UserDefaults.standard.data(forKey: USER_DEFAULTS_KEY_WIDGET_DATA)
else {
return nil
}
do {
guard let array = try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(unarchivedObject) as? [WidgetData] else {
fatalError("loadWidgetDataArray - Can't get Array")
}
return array
} catch {
fatalError("loadWidgetDataArray - Can't encode data: \(error)")
}
}
But if you are making a new app, you should better consider using Codable
.
NSKeyedUnarchiver returning nil when retrieving custom class
You can use this method to unarchive the data.
https://developer.apple.com/documentation/foundation/nskeyedunarchiver/2963379-unarchivedobject
NSKeyedUnarchiver.unarchivedObject(ofClasses:from:)
You can write your unarchiving code as;
let data = try Data(contentsOf: filePath)
let object = try NSKeyedUnarchiver.unarchivedObject(ofClasses:[object.self, UIImage.self], from: data)
Hopefully, it works.
PS. One tip about naming classes. They should always start with capital letter.
EDIT: You should add UIImage.self also when trying to unarchive.
and you should change your archive method as seen below.
NSKeyedArchiver.archivedData(withRootObject: data, requiringSecureCoding: true)
Your model should also satisfy NSSecureCoding protocol when using this unarchive method.
extension object : NSSecureCoding {
static var supportsSecureCoding: Bool {
return true
}
}
Related Topics
How to Reload a UI View's Content Swift
Spritekit Not Deallocating All Used Memory
Check for Nil with Guard Instead of If
Difference Between Awakefromnib() and Viewdidload() in Swift
Correct Handling/Cleanup/Etc of Cadisplaylink in Swift Custom Animation
Use of Undeclared Type 'Viewcontroller' When Unit Testing My Own Viewcontroller in Swift
App Crashes When Playing Audio on iOS13.1
How to Get Data from Observedobject with Onreceive in Swiftui
Swift - How to Set Cookie in Nsmutableurlrequest
Swift Closures - Capturing Self as Weak
Example of Dispatch_Once in Swift
How to Compile Latest Swift Version on Older Xcode
Swift: Popover Dismiss Callback
Expression Implicitly Coerced from 'String' to Any
Typecasting or Initialization, Which Is Better in Swift
Detecting If Wifi or Bluetooth Is Turned on or Off by the User
Getting Unresolved Identifier 'Self' in Swiftui Code Trying to Use Timer.Scheduledtimer