Reputation: 1430
I am trying to save a very simple object using NSKeyedArchiver in swift, and I see that it is saving correctly, with values, but whenever it tries to decode the saved data it fails. I am new to swift and I have tried googling and os_log (ing) everything, but I can't see where the problem lies. Here is the Object I am trying to save...
class TrackedAmount: NSObject, NSCoding {
var cups: Int
var fraction: Float?
struct PropertyKey {
static let cups = "cups"
static let fraction = "fraction"
}
init?(cups: Int, fraction: Float?) {
os_log("Running init? function", log: .default, type: .debug)
if(cups < 0) {
os_log("Cups less than 0. Returning nil", log: .default, type: .debug)
return nil
}
self.cups = cups
self.fraction = fraction
}
required convenience init? coder aDecoder: NSCoder) {
os_log("Running required convenience init? function", log: .default, type: .debug)
guard let cups = aDecoder.decodeObject(forKey: PropertyKey.cups) as? Int else {
os_log("Unable to decode cups", log: .default, type: .debug)
return nil
}
guard let fraction = aDecoder.decodeObject(forKey: PropertyKey.fraction) as? Float else {
os_log("Unable to decode fraction", log: .default, type: .debug)
return nil
}
self.init(cups: cups, fraction: fraction)
}
func encode(with aCoder: NSCoder) {
aCoder.encode(cups, forKey: PropertyKey.cups)
aCoder.encode(fraction, forKey: PropertyKey.fraction)
}
Then in my ViewController I am trying to get and save them like so,...
private func saveAmount() {
trackedToday = TrackedAmount(cups: selectedCups, fraction: selectedFraction)
print("data.... cups: " + String(trackedToday!.cups) + " fractions: " + String(trackedToday!.fraction!))
let fullPath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0].appendingPathComponent("dailytracked")
do {
let data = try NSKeyedArchiver.archivedData(withRootObject: trackedToday!, requiringSecureCoding: false)
try data.write(to: fullPath)
} catch {
os_log("Unable to save tracking amount", log: .default, type: .debug)
}
}
private func loadDailyTracked() -> TrackedAmount? {
let fullPath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0].appendingPathComponent("dailytracked")
if let nsData = NSData(contentsOf: fullPath) {
do {
let data = Data(referencing: nsData)
if let loadedData = try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data) as? TrackedAmount {
os_log("it finally worked", log: .default, type: .debug)
return loadedData
}
} catch {
os_log("Couldn't read from file", log: .default, type: .debug)
return nil
}
return nil
}
It is saving correctly but whenever I try to run the loadDailyTracked() method I get the following in the output section in xcode...
Running required convenience init? function
Unable to decode cups
I can't seem to figure out why it can't decode the cups, I know the data is being saved since none of the logs show any failure except for when it is trying to read from the saved data. I even logged the information before saving and it is showing the correct data. Anyone have any ideas? I am really new to IOS and Swift and I just can't figure this out. Thank you.
*Side note, if you need more code or information I am happy to provide it, I was just trying to keep the post from being too big if it didn't need to be.
Upvotes: 1
Views: 228
Reputation: 285260
In terms of NSCoder
scalar types like Int
and Float
are not objects and the dedicated methods don't return optionals
required convenience init? coder aDecoder: NSCoder) {
os_log("Running required convenience init? function", log: .default, type: .debug)
let cups = aDecoder.decodeInteger(forKey: PropertyKey.cups)
let fraction = aDecoder.decodeFloat(forKey: PropertyKey.fraction)
self.init(cups: cups, fraction: fraction)
}
NSCoding
in Swift is pretty heavy. It's highly recommended to use the Codable
protocol to serialize structs and classes.
Upvotes: 2