Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unarchive Array with NSKeyedUnarchiver unarchivedObject(ofClass:from:)

Tags:

Since upgrading to Swift 4.2 I've found that many of the NSKeyedUnarchiver and NSKeyedArchiver methods have been deprecated and we must now use the type method static func unarchivedObject<DecodedObjectType>(ofClass: DecodedObjectType.Type, from: Data) -> DecodedObjectType? to unarchive data.

I have managed to successfully archive an Array of my bespoke class WidgetData, which is an NSObject subclass:

private static func archiveWidgetDataArray(widgetDataArray : [WidgetData]) -> NSData {      guard let data = try? NSKeyedArchiver.archivedData(withRootObject: widgetDataArray as Array, requiringSecureCoding: false) as NSData         else { fatalError("Can't encode data") }      return data  } 

The problem comes when I try to unarchive this data:

static func loadWidgetDataArray() -> [WidgetData]? {      if isKeyPresentInUserDefaults(key: USER_DEFAULTS_KEY_WIDGET_DATA) {          if let unarchivedObject = UserDefaults.standard.object(forKey: USER_DEFAULTS_KEY_WIDGET_DATA) as? Data {              //THIS FUNCTION HAS NOW BEEN DEPRECATED:             //return NSKeyedUnarchiver.unarchiveObject(with: unarchivedObject as Data) as? [WidgetData]              guard let nsArray = try? NSKeyedUnarchiver.unarchivedObject(ofClass: NSArray.self, from: unarchivedObject as Data) else {                 fatalError("loadWidgetDataArray - Can't encode data")             }              guard let array = nsArray as? Array<WidgetData> else {                 fatalError("loadWidgetDataArray - Can't get Array")             }              return array          }      }      return nil  } 

But this fails, as using Array.self instead of NSArray.self is disallowed. What am I doing wrong and how can I fix this to unarchive my Array?

like image 882
Geoff H Avatar asked Jul 23 '18 21:07

Geoff H


1 Answers

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, use Data instead

  • Avoid using try? which disposes error info useful for debugging

  • Remove 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.

like image 114
OOPer Avatar answered Nov 15 '22 19:11

OOPer