3

I just released an app to the app store and one of my patrons let me know that I should change the data type that I was previously storing as an Integer, using the NSKeyedArchiver, to a Double.

Easy enough to change the app's data model but when I reload the app on my test device, the NSKeyedUnarchiver obviously doesn't want to decode an Integer as a Double and throws an NSInvalidUnarchiveOperation Exception.

I was wondering how any other iOS Dev's would handle this situation. I'd hate to erase all of my users' previously saved data but that's the only solution I'm seeing.

My code is posted below. I've commented out a few solutions I tried to no avail

    required convenience init?(coder aDecoder: NSCoder){

       func decodeDoubles(coder aDecoder: NSCoder) throws-> (Double, Double){
           print("Getting in here")
           /* These are stored as Integers in previous version */
           let myEarned =  aDecoder.decodeDoubleForKey(PropertyKey.earnedKey)
           let myTotal = aDecoder.decodeDoubleForKey(PropertyKey.totalKey)

           /* App Crashes here - exception not caught */
           print("After decode attempt")
           return (myEarned, myTotal)
       }

       let myID = aDecoder.decodeIntegerForKey(PropertyKey.idKey)
       let myName = aDecoder.decodeObjectForKey(PropertyKey.nameKey) as! String
       let myWeight = aDecoder.decodeIntegerForKey(PropertyKey.weightKey)
           /* Throws exception */
           //let myEarned =  aDecoder.decodeDoubleForKey(PropertyKey.earnedKey) 
           //let myTotal = try! aDecoder.decodeDoubleForKey(PropertyKey.totalKey)


       var myEarned: Double = 0
       var myTotal: Double = 0

       do {
          (myEarned, myTotal) = try decodeDoubles(coder: aDecoder)
       } catch {
           print("Exception caught - \(error)")
           myEarned = Double(aDecoder.decodeIntegerForKey(PropertyKey.earnedKey))
           myTotal = Double(aDecoder.decodeIntegerForKey(PropertyKey.totalKey))
    }

       self.init(id: myID, name: myName, weight: myWeight, earned: myEarned, total: myTotal)
   }

1 Answers1

4

You might need to make a function to sort of upgrade the archive, as the app loads, read in the key as an Integer, and write it back as a double, then the rest of your app can read and write it as a double normally. you will need a new key to flag that you have done the upgrade so you dont do it again, and dont do it for new users.

Fonix
  • 11,447
  • 3
  • 45
  • 74
  • That is how I would do it. – Steve Rosenberg Mar 30 '16 at 03:22
  • That's a great idea! I thought of that but wasn't exactly sure where I could store the flag to avoid having the same issue when trying to decode an integer as a double. I'm thinking I may try to save a value to NSUserDefaults or adding a flag value to the NSKeyedArchiver. Any suggestions? – John Luke Garofalo Mar 30 '16 at 03:38
  • saving the flag to NSUserDefaults is probably easier. also just have a try/catch in the function so that if it cant read in the integer, it will assume its a new user and mark the flag so it wont try do it again (or the value is somehow not present and doesnt need to be upgraded anyway) – Fonix Mar 30 '16 at 03:41
  • You could also store a version number of the document format in the archive and run the migration code based on the read version number. – Lukáš Kubánek Jul 19 '17 at 07:16