I'm trying to store a custom class in UserDefaults
, however I'm getting the "Attempt to insert non-property list"
error as soon as the app starts. I have successfully stored arrays of custom classes, so I followed the same principle, but something is wrong.
This is my class:
import Foundation
public class PlanRouteFilters: NSObject, NSCoding, Codable {
var favoriteLines: Bool
var routeType: Int
var bus: Bool
var train: Bool
var subway: Bool
var electric: Bool
var sharedCar: Bool
var bike: Bool
var electricScooter: Bool
var providers: [Provider]?
override init() {
self.favoriteLines = false
self.routeType = 1
self.bus = false
self.train = false
self.subway = false
self.electric = false
self.sharedCar = false
self.bike = false
self.electricScooter = false
self.providers = []
}
init(favLines: Bool, rType: Int, bus: Bool, train: Bool, subway: Bool, electric: Bool, sCar: Bool, bike: Bool, eScooter: Bool, providers: [Provider]?) {
self.favoriteLines = favLines
self.routeType = rType
self.bus = bus
self.train = train
self.subway = subway
self.electric = electric
self.sharedCar = sCar
self.bike = bike
self.electricScooter = eScooter
self.providers = providers
}
//MARK: NSCoding protocol methods
public func encode(with aCoder: NSCoder){
aCoder.encode(self.favoriteLines, forKey: "favoriteLines")
aCoder.encode(self.routeType, forKey: "RouteType")
aCoder.encode(self.bus, forKey: "bus")
aCoder.encode(self.train, forKey: "train")
aCoder.encode(self.subway, forKey: "subway")
aCoder.encode(self.electric, forKey: "electric")
aCoder.encode(self.sharedCar, forKey: "sharedCar")
aCoder.encode(self.bike, forKey: "bike")
aCoder.encode(self.electricScooter, forKey: "electricScooter")
aCoder.encode(self.providers, forKey: "providers")
}
public required init(coder decoder: NSCoder) {
self.favoriteLines = decoder.decodeBool(forKey: "favoriteLines")
self.routeType = decoder.decodeInteger(forKey: "routeType")
self.bus = decoder.decodeBool(forKey: "bus")
self.train = decoder.decodeBool(forKey: "train")
self.subway = decoder.decodeBool(forKey: "subway")
self.electric = decoder.decodeBool(forKey: "electric")
self.sharedCar = decoder.decodeBool(forKey: "sharedCar")
self.bike = decoder.decodeBool(forKey: "bike")
self.electricScooter = decoder.decodeBool(forKey: "electricScooter")
self.providers = decoder.decodeObject(forKey: "providers") as? [Provider]
}
}
This is how I set and get the object:
var planRouteFilters: PlanRouteFilters {
get {
var filters = PlanRouteFilters()
let data = self.userSettings.settings.object(forKey: "planRouteFilters") as? Data
if nil != data {
filters = try! NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data!) as! PlanRouteFilters
}
return filters
}
set {
let data = try! NSKeyedArchiver.archivedData(withRootObject: newValue, requiringSecureCoding: false)
self.userSettings.settings.setValue(data, forKey: "planRouteFilters")
self.objectWillChange.send()
}
}
And this is how I create the userDefaults:
import Foundation
struct UserSettings {
var settings: UserDefaults
init() {
self.settings = UserDefaults.standard
self.settings.register(
defaults: [
"userCity": "",
"showUserCityActionSheet": true,
"showTutorial": 1,
"initialPage": 1,
"favoriteStops": [Place](),
"history": [Place](), //Maximum of 10 places stored
"notifications": [MoveMeNotification](),
"planRouteFilters": PlanRouteFilters()
])
}
}
If I remove the default value for the PlanRouteFilters the app starts, but the values are not used throughout the app. Is this where I am wrong? Should I provide the default value in some other way?
Thanks!
My Provider
class:
public class Provider: NSObject, NSCoding, Codable {
let name: String
init(name: String) {
self.Name = name
}
public func encode(with aCoder: NSCoder) {
aCoder.encode(self.Name, forKey: "Name")
}
public required init(coder decoder: NSCoder) {
self.Name = decoder.decodeObject(forKey: "Name") as! String
}
}
UPDATE:
Ok, I was not able to solve this issue. However, I figured I did not need to have a default value in the userSettings. That allows me to move on. However, that is specific to my case. For any of those that don't have this option, take a look at @LeoDabus answers.