I have the following decoder code. It always executes the catch block. The error I get is as follows:
This decoder will only decode classes that adopt NSSecureCoding
if let dataToRetrieve = UserDefaults.standard.data(forKey: "currentPlayerToon") {
do {
let returnedPlayerInformation = try NSKeyedUnarchiver.unarchivedObject(ofClass: PlayerClass.self, from: dataToRetrieve)
print("Success")
} catch {
print(error)
}
}
Here is my save. This always succeeds.
do {
let dataToSave = try NSKeyedArchiver.archivedData(withRootObject: cachedToonToSave, requiringSecureCoding: false)
UserDefaults.standard.set(dataToSave, forKey: "currentPlayerToon")
print("saving worked")
} catch {
print("saving failed")
}
In case this is requested, here is my class declaration. It's long:
class PlayerClass: NSObject, NSCoding {
var toonName : String
var toonLevel : Float
var toonCurrentHealth : Int
var toonCurrentEnergy : Int
var toonHealthPotionCount : Int
var toonEnergyPotionCount : Int
var toonRealityShardCount : Int
var toonGoldCoinCount : Int
var toonPistolAmmoCount : Int
var toonShotgunAmmoCount : Int
var toonRifleAmmoCount : Int
var toonDamageBoost : Int
var toonStaminaBoost : Int
var toonDefensiveBoost : Int
var toonAwarenessBoost : Int
var toonEquippedWeaponOne : Int
var toonEquippedWeaponTwo : Int
var toonEquippedWeaponThree : Int
var toonEquippedArmorOne : Int
var toonEquippedArmorTwo : Int
var toonEquippedArmorThree : Int
var toonEquippedArmorFour : Int
var toonEquippedArmorFive : Int
var toonEquippedArmorSix : Int
var toonInventorySlotOne : Int
var toonInventorySlotTwo : Int
var toonInventorySlotThree : Int
var toonInventorySlotFour : Int
var toonInventorySlotFive : Int
var toonInventorySlotSix : Int
var toonInventorySlotSeven : Int
var toonInventorySlotEight : Int
var toonInventorySlotNine : Int
var toonInventorySlotTen : Int
var toonInventorySlotEleven : Int
var toonInventorySlotTwelve : Int
var toonInventorySlotThirteen : Int
var toonInventorySlotFourteen : Int
var toonInventorySlotFifteen : Int
var toonAbilityOne : Int
var toonAbilityTwo : Int
var toonAbilityThree : Int
var toonAbilityFour : Int
var abilityOneUseTimestamp : String
var abilityTwoUseTimestamp : String
var abilityThreeUseTimestamp : String
var abilityFourUseTimestamp : String
var lastPromoDate : String
var lastFreeLife : String
init(
toonName : String,
toonLevel : Float,
toonCurrentHealth : Int,
toonCurrentEnergy : Int,
toonHealthPotionCount : Int,
toonEnergyPotionCount : Int,
toonRealityShardCount : Int,
toonGoldCoinCount : Int,
toonPistolAmmoCount : Int,
toonShotgunAmmoCount : Int,
toonRifleAmmoCount : Int,
toonDamageBoost : Int,
toonStaminaBoost : Int,
toonDefensiveBoost : Int,
toonAwarenessBoost : Int,
toonEquippedWeaponOne : Int,
toonEquippedWeaponTwo : Int,
toonEquippedWeaponThree : Int,
toonEquippedArmorOne : Int,
toonEquippedArmorTwo : Int,
toonEquippedArmorThree : Int,
toonEquippedArmorFour : Int,
toonEquippedArmorFive : Int,
toonEquippedArmorSix : Int,
toonInventorySlotOne : Int,
toonInventorySlotTwo : Int,
toonInventorySlotThree : Int,
toonInventorySlotFour : Int,
toonInventorySlotFive : Int,
toonInventorySlotSix : Int,
toonInventorySlotSeven : Int,
toonInventorySlotEight : Int,
toonInventorySlotNine : Int,
toonInventorySlotTen : Int,
toonInventorySlotEleven : Int,
toonInventorySlotTwelve : Int,
toonInventorySlotThirteen : Int,
toonInventorySlotFourteen : Int,
toonInventorySlotFifteen : Int,
toonAbilityOne : Int,
toonAbilityTwo : Int,
toonAbilityThree : Int,
toonAbilityFour : Int,
abilityOneUseTimestamp : String,
abilityTwoUseTimestamp : String,
abilityThreeUseTimestamp : String,
abilityFourUseTimestamp : String,
lastPromoDate : String,
lastFreeLife : String) {
self.toonName = toonName
self.toonLevel = toonLevel
self.toonCurrentHealth = toonCurrentHealth
self.toonCurrentEnergy = toonCurrentEnergy
self.toonHealthPotionCount = toonHealthPotionCount
self.toonEnergyPotionCount = toonEnergyPotionCount
self.toonRealityShardCount = toonRealityShardCount
self.toonGoldCoinCount = toonGoldCoinCount
self.toonPistolAmmoCount = toonPistolAmmoCount
self.toonShotgunAmmoCount = toonShotgunAmmoCount
self.toonRifleAmmoCount = toonRifleAmmoCount
self.toonDamageBoost = toonDamageBoost
self.toonStaminaBoost = toonStaminaBoost
self.toonDefensiveBoost = toonDefensiveBoost
self.toonAwarenessBoost = toonAwarenessBoost
self.toonEquippedWeaponOne = toonEquippedWeaponOne
self.toonEquippedWeaponTwo = toonEquippedWeaponTwo
self.toonEquippedWeaponThree = toonEquippedWeaponThree
self.toonEquippedArmorOne = toonEquippedArmorOne
self.toonEquippedArmorTwo = toonEquippedArmorTwo
self.toonEquippedArmorThree = toonEquippedArmorThree
self.toonEquippedArmorFour = toonEquippedArmorFour
self.toonEquippedArmorFive = toonEquippedArmorFive
self.toonEquippedArmorSix = toonEquippedArmorSix
self.toonInventorySlotOne = toonInventorySlotOne
self.toonInventorySlotTwo = toonInventorySlotTwo
self.toonInventorySlotThree = toonInventorySlotThree
self.toonInventorySlotFour = toonInventorySlotFour
self.toonInventorySlotFive = toonInventorySlotFive
self.toonInventorySlotSix = toonInventorySlotSix
self.toonInventorySlotSeven = toonInventorySlotSeven
self.toonInventorySlotEight = toonInventorySlotEight
self.toonInventorySlotNine = toonInventorySlotNine
self.toonInventorySlotTen = toonInventorySlotTen
self.toonInventorySlotEleven = toonInventorySlotEleven
self.toonInventorySlotTwelve = toonInventorySlotTwelve
self.toonInventorySlotThirteen = toonInventorySlotThirteen
self.toonInventorySlotFourteen = toonInventorySlotFourteen
self.toonInventorySlotFifteen = toonInventorySlotFifteen
self.toonAbilityOne = toonAbilityOne
self.toonAbilityTwo = toonAbilityTwo
self.toonAbilityThree = toonAbilityThree
self.toonAbilityFour = toonAbilityFour
self.abilityOneUseTimestamp = abilityOneUseTimestamp
self.abilityTwoUseTimestamp = abilityTwoUseTimestamp
self.abilityThreeUseTimestamp = abilityThreeUseTimestamp
self.abilityFourUseTimestamp = abilityFourUseTimestamp
self.lastPromoDate = lastPromoDate
self.lastFreeLife = lastFreeLife
}
required init(coder decoder: NSCoder) {
self.toonName = decoder.decodeObject(forKey: "toonName") as? String ?? ""
self.toonLevel = decoder.decodeFloat(forKey: "toonLevel")
self.toonCurrentHealth = decoder.decodeInteger(forKey: "toonCurrentHealth")
self.toonCurrentEnergy = decoder.decodeInteger(forKey: "toonCurrentEnergy")
self.toonHealthPotionCount = decoder.decodeInteger(forKey: "toonHealthPotionCount")
self.toonEnergyPotionCount = decoder.decodeInteger(forKey: "toonEnergyPotionCount")
self.toonRealityShardCount = decoder.decodeInteger(forKey: "toonRealityShardCount")
self.toonGoldCoinCount = decoder.decodeInteger(forKey: "toonGoldCoinCount")
self.toonPistolAmmoCount = decoder.decodeInteger(forKey: "toonPistolAmmoCount")
self.toonShotgunAmmoCount = decoder.decodeInteger(forKey: "toonShotgunAmmoCount")
self.toonRifleAmmoCount = decoder.decodeInteger(forKey: "toonRifleAmmoCount")
self.toonDamageBoost = decoder.decodeInteger(forKey: "toonDamageBoost")
self.toonStaminaBoost = decoder.decodeInteger(forKey: "toonStaminaBoost")
self.toonDefensiveBoost = decoder.decodeInteger(forKey: "toonDefensiveBoost")
self.toonAwarenessBoost = decoder.decodeInteger(forKey: "toonAwarenessBoost")
self.toonEquippedWeaponOne = decoder.decodeInteger(forKey: "toonEquippedWeaponOne")
self.toonEquippedWeaponTwo = decoder.decodeInteger(forKey: "toonEquippedWeaponTwo")
self.toonEquippedWeaponThree = decoder.decodeInteger(forKey: "toonEquippedWeaponThree")
self.toonEquippedArmorOne = decoder.decodeInteger(forKey: "toonEquippedArmorOne")
self.toonEquippedArmorTwo = decoder.decodeInteger(forKey: "toonEquippedArmorTwo")
self.toonEquippedArmorThree = decoder.decodeInteger(forKey: "toonEquippedArmorThree")
self.toonEquippedArmorFour = decoder.decodeInteger(forKey: "toonEquippedArmorFour")
self.toonEquippedArmorFive = decoder.decodeInteger(forKey: "toonEquippedArmorFive")
self.toonEquippedArmorSix = decoder.decodeInteger(forKey: "toonEquippedArmorSix")
self.toonInventorySlotOne = decoder.decodeInteger(forKey: "toonInventorySlotOne")
self.toonInventorySlotTwo = decoder.decodeInteger(forKey: "toonInventorySlotTwo")
self.toonInventorySlotThree = decoder.decodeInteger(forKey: "toonInventorySlotThree")
self.toonInventorySlotFour = decoder.decodeInteger(forKey: "toonInventorySlotFour")
self.toonInventorySlotFive = decoder.decodeInteger(forKey: "toonInventorySlotFive")
self.toonInventorySlotSix = decoder.decodeInteger(forKey: "toonInventorySlotSix")
self.toonInventorySlotSeven = decoder.decodeInteger(forKey: "toonInventorySlotSeven")
self.toonInventorySlotEight = decoder.decodeInteger(forKey: "toonInventorySlotEight")
self.toonInventorySlotNine = decoder.decodeInteger(forKey: "toonInventorySlotNine")
self.toonInventorySlotTen = decoder.decodeInteger(forKey: "toonInventorySlotTen")
self.toonInventorySlotEleven = decoder.decodeInteger(forKey: "toonInventorySlotEleven")
self.toonInventorySlotTwelve = decoder.decodeInteger(forKey: "toonInventorySlotTwelve")
self.toonInventorySlotThirteen = decoder.decodeInteger(forKey: "toonInventorySlotThirteen")
self.toonInventorySlotFourteen = decoder.decodeInteger(forKey: "toonInventorySlotFourteen")
self.toonInventorySlotFifteen = decoder.decodeInteger(forKey: "toonInventorySlotFifteen")
self.toonAbilityOne = decoder.decodeInteger(forKey: "toonAbilityOne")
self.toonAbilityTwo = decoder.decodeInteger(forKey: "toonAbilityTwo")
self.toonAbilityThree = decoder.decodeInteger(forKey: "toonAbilityThree")
self.toonAbilityFour = decoder.decodeInteger(forKey: "toonAbilityFour")
self.abilityOneUseTimestamp = decoder.decodeObject(forKey: "abilityOneUseTimestamp") as! String
self.abilityTwoUseTimestamp = decoder.decodeObject(forKey: "abilityTwoUseTimestamp") as! String
self.abilityThreeUseTimestamp = decoder.decodeObject(forKey: "abilityThreeUseTimestamp") as! String
self.abilityFourUseTimestamp = decoder.decodeObject(forKey: "abilityFourUseTimestamp") as! String
self.lastPromoDate = decoder.decodeObject(forKey: "lastPromoDate") as? String ?? ""
self.lastFreeLife = decoder.decodeObject(forKey: "lastFreeLife") as? String ?? ""
}
func encode(with coder: NSCoder) {
coder.encode(toonName, forKey: "toonName")
coder.encode(toonLevel, forKey: "toonLevel")
coder.encode(toonCurrentHealth, forKey: "toonCurrentHealth")
coder.encode(toonCurrentEnergy, forKey: "toonCurrentEnergy")
coder.encode(toonHealthPotionCount, forKey: "toonHealthPotionCount")
coder.encode(toonEnergyPotionCount, forKey: "toonEnergyPotionCount")
coder.encode(toonRealityShardCount, forKey: "toonRealityShardCount")
coder.encode(toonGoldCoinCount, forKey: "toonGoldCoinCount")
coder.encode(toonPistolAmmoCount, forKey: "toonPistolAmmoCount")
coder.encode(toonShotgunAmmoCount, forKey: "toonShotgunAmmoCount")
coder.encode(toonRifleAmmoCount, forKey: "toonRifleAmmoCount")
coder.encode(toonDamageBoost, forKey: "toonDamageBoost")
coder.encode(toonStaminaBoost, forKey: "toonStaminaBoost")
coder.encode(toonDefensiveBoost, forKey: "toonDefensiveBoost")
coder.encode(toonAwarenessBoost, forKey: "toonAwarenessBoost")
coder.encode(toonEquippedWeaponOne, forKey: "toonEquippedWeaponOne")
coder.encode(toonEquippedWeaponTwo, forKey: "toonEquippedWeaponTwo")
coder.encode(toonEquippedWeaponThree, forKey: "toonEquippedWeaponThree")
coder.encode(toonEquippedArmorOne, forKey: "toonEquippedArmorOne")
coder.encode(toonEquippedArmorTwo, forKey: "toonEquippedArmorTwo")
coder.encode(toonEquippedArmorThree, forKey: "toonEquippedArmorThree")
coder.encode(toonEquippedArmorFour, forKey: "toonEquippedArmorFour")
coder.encode(toonEquippedArmorFive, forKey: "toonEquippedArmorFive")
coder.encode(toonEquippedArmorSix, forKey: "toonEquippedArmorSix")
coder.encode(toonInventorySlotOne, forKey: "toonInventorySlotOne")
coder.encode(toonInventorySlotTwo, forKey: "toonInventorySlotTwo")
coder.encode(toonInventorySlotThree, forKey: "toonInventorySlotThree")
coder.encode(toonInventorySlotFour, forKey: "toonInventorySlotFour")
coder.encode(toonInventorySlotFive, forKey: "toonInventorySlotFive")
coder.encode(toonInventorySlotSix, forKey: "toonInventorySlotSix")
coder.encode(toonInventorySlotSeven, forKey: "toonInventorySlotSeven")
coder.encode(toonInventorySlotEight, forKey: "toonInventorySlotEight")
coder.encode(toonInventorySlotNine, forKey: "toonInventorySlotNine")
coder.encode(toonInventorySlotTen, forKey: "toonInventorySlotTen")
coder.encode(toonInventorySlotEleven, forKey: "toonInventorySlotEleven")
coder.encode(toonInventorySlotTwelve, forKey: "toonInventorySlotTwelve")
coder.encode(toonInventorySlotThirteen, forKey: "toonInventorySlotThirteen")
coder.encode(toonInventorySlotFourteen, forKey: "toonInventorySlotFourteen")
coder.encode(toonInventorySlotFifteen, forKey: "toonInventorySlotFifteen")
coder.encode(toonAbilityOne, forKey: "toonAbilityOne")
coder.encode(toonAbilityTwo, forKey: "toonAbilityTwo")
coder.encode(toonAbilityThree, forKey: "toonAbilityThree")
coder.encode(toonAbilityFour, forKey: "toonAbilityFour")
coder.encode(abilityOneUseTimestamp, forKey: "abilityOneUseTimestamp")
coder.encode(abilityTwoUseTimestamp, forKey: "abilityTwoUseTimestamp")
coder.encode(abilityThreeUseTimestamp, forKey: "abilityThreeUseTimestamp")
coder.encode(abilityFourUseTimestamp, forKey: "abilityFourUseTimestamp")
coder.encode(lastPromoDate, forKey: "lastPromoDate")
coder.encode(lastFreeLife, forKey: "lastFreeLife")
}
}
CodePudding user response:
Apple wants everyone to use NSSecureCoding instead of just NSCoding. You need to change your class to conform to NSSecureCoding
. Then you pass true
to the requiringSecureCoding
parameter when you create the archive.
// Change NSCoding to NSSecureCoding
class PlayerClass: NSObject, NSSecureCoding {
// The following is needed as well
static var supportsSecureCoding: Bool { return true }
var toonName : String
var toonLevel : Float
// and the rest as you already have it
and:
let dataToSave = try NSKeyedArchiver.archivedData(withRootObject: cachedToonToSave, requiringSecureCoding: true)
With just those changes your code should work.
You will need to resave the updated data in user defaults before you can load it back in.
CodePudding user response:
In addition to the good advice using NSSecureCoding
,
you could try this example code with unarchiveTopLevelObjectWithData
, works for me:
if let dataToRetrieve = UserDefaults.standard.data(forKey: "currentPlayerToon") {
do {
// --- here
if let returnedPlayerInformation = try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(dataToRetrieve) as? PlayerClass {
print("---> YES DECODED")
} else {
print("---> NOT DECODED")
}
} catch {
print("---> catching error")
}
}