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")
}
}
