我有一些我想要解码的键,但它只解码我的第一个字符串然后它会出错。
class Profile: NSCoder, NSCoding {
struct Constants {
// Age
static let minimumAge: Int = 5
static let maximumAge: Int = 120
static let defaultAge: Int = 25
// Gender
static let defaultGender: Int = 0
// Daily meals
static let defaultDailyMeals: Int = 3
static let minimumDailyMeals: Int = 1
static let maximumDailyMeals: Int = 10
// Do you train
static let defaultIsTraining: Bool = false
}
//MARK: Properties
private var name: String
private var age: Int
private var gender: Int
private var target: Int
private var dailyMeals: Int
private var isTraining: Bool
private var trainingWhen: Int?
private var trainingDays: [(Int)];
//MARK: Archiving Paths
static let DocumentsDirectory = FileManager().urls(for: .documentDirectory, in: .userDomainMask).first!
static let ArchiveURL = DocumentsDirectory.appendingPathComponent("profile")
//MARK: Types
struct PropertyKey {
static let name = "profileName"
static let age = "profileAge"
static let gender = "profileGender"
static let target = "profileTarget"
static let dailyMeals = "profileDailyMeals"
static let isTraining = "profileIsTraining"
static let trainingWhen = "profileTrainingWhen"
static let trainingDays = "trainingDays"
}
// Main init
init?(name: String, age: Int, gender: Int, target: Int, dailyMeals: Int, isTraining: Bool, trainingWhen: Int?, trainingDays: [(Int)]) {
guard !name.isEmpty else {
print("Name empty")
return nil
}
guard age > Constants.minimumAge && age < Constants.maximumAge else {
print("Age not in range")
return nil
}
self.name = name
self.age = age
self.gender = gender
self.target = target
self.dailyMeals = dailyMeals
self.isTraining = isTraining
self.trainingWhen = trainingWhen
self.trainingDays = trainingDays
}
//MARK: NSCoding
func encode(with aCoder: NSCoder) {
aCoder.encode(self.name, forKey: PropertyKey.name)
aCoder.encode(self.age, forKey: PropertyKey.age)
aCoder.encode(self.gender, forKey: PropertyKey.gender)
aCoder.encode(self.target, forKey: PropertyKey.target)
aCoder.encode(self.dailyMeals, forKey: PropertyKey.dailyMeals)
aCoder.encode(self.isTraining, forKey: PropertyKey.isTraining)
aCoder.encode(self.trainingWhen, forKey: PropertyKey.trainingWhen)
aCoder.encode(self.trainingDays, forKey: PropertyKey.trainingDays)
}
func dump_data(){
print("Name: " + self.name)
print("Age: " + String(self.age))
print("Gender: " + String(self.gender))
print("Target: " + String(self.target))
print("Daily Meals: " + String(self.dailyMeals))
print("Does train?: " + String(self.isTraining))
print("When: " + String(describing: self.trainingWhen))
print("Days: " + String(describing: self.trainingDays))
}
required convenience init?(coder aDecoder: NSCoder) {
guard let name = aDecoder.decodeObject(forKey: PropertyKey.name) as? String else {
print("Unable to decode the name for a Profile object.")
return nil
}
print("Decoded: Name - \(name)")
guard let age = aDecoder.decodeObject(forKey: PropertyKey.age) as? Int else {
print("Unable to decode the age for a Profile object.")
return nil
}
guard let gender = aDecoder.decodeObject(forKey: PropertyKey.gender) as? Int else {
print("Unable to decode the gender for a Profile object.")
return nil
}
guard let target = aDecoder.decodeObject(forKey: PropertyKey.target) as? Int else {
print("Unable to decode the target for a Profile object.")
return nil
}
guard let dailyMeals = aDecoder.decodeObject(forKey: PropertyKey.dailyMeals) as? Int else {
print("Unable to decode the daily meals for a Profile object.")
return nil
}
guard let isTraining = aDecoder.decodeObject(forKey: PropertyKey.isTraining) as? Bool else {
print("Unable to decode the training state for a Profile object.")
return nil
}
let trainingWhen: Int? = aDecoder.decodeObject(forKey: PropertyKey.trainingWhen) as? Int ?? nil
let trainingDays: [(Int)] = aDecoder.decodeObject(forKey: PropertyKey.trainingDays) as? [(Int)] ?? []
// Must call designated initializer.
self.init(name: name, age: age, gender: gender, target: target, dailyMeals: dailyMeals, isTraining: isTraining, trainingWhen: trainingWhen, trainingDays: trainingDays)
}
我收到的错误消息是
无法解码Profile对象的年龄。
只要我知道这意味着我的aDecoder.decodeObject(forKey:PropertyKey.gender)为? Int返回nil,我完全不知道为什么会发生这种情况,因为我可以在代码中看到它进行编码。 :/
答案 0 :(得分:3)
您应该使用decodeInteger(forKey:_)
方法,如下所示:
self.age = aDecoder.decodeInteger(forKey: PropertyKey.age)
话虽如此,我通常在这些情况下做的事情(考虑到你只需要一个类的实例)是这样的:
//: Playground - noun: a place where people can play
import UIKit
class Profile: NSCoder, NSCoding {
struct Constants {
// Age
static let minimumAge: Int = 5
static let maximumAge: Int = 120
static let defaultAge: Int = 25
// Gender
static let defaultGender: Int = 0
// Daily meals
static let defaultDailyMeals: Int = 3
static let minimumDailyMeals: Int = 1
static let maximumDailyMeals: Int = 10
// Do you train
static let defaultIsTraining: Bool = false
}
//MARK: Properties
var name: String = ""
var age: Int = 0
var gender: Int = 0
var target: Int = 0
var dailyMeals: Int = 0
var isTraining: Bool = false
var trainingWhen: Int? = nil
var trainingDays = [Int]();
//MARK: Archiving Paths
static let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0].path
static let fileName = "profile"
static let path = "\(Profile.documentsDirectory)/\(fileName)"
//MARK: Types
struct PropertyKey {
static let name = "profileName"
static let age = "profileAge"
static let gender = "profileGender"
static let target = "profileTarget"
static let dailyMeals = "profileDailyMeals"
static let isTraining = "profileIsTraining"
static let trainingWhen = "profileTrainingWhen"
static let trainingDays = "trainingDays"
}
// Main init
static var shared = Profile()
fileprivate override init() { }
//MARK: NSCoding
func encode(with archiver: NSCoder) {
archiver.encode(self.name, forKey: PropertyKey.name)
archiver.encode(self.age, forKey: PropertyKey.age)
archiver.encode(self.gender, forKey: PropertyKey.gender)
archiver.encode(self.target, forKey: PropertyKey.target)
archiver.encode(self.dailyMeals, forKey: PropertyKey.dailyMeals)
archiver.encode(self.isTraining, forKey: PropertyKey.isTraining)
archiver.encode(self.trainingWhen, forKey: PropertyKey.trainingWhen)
archiver.encode(self.trainingDays, forKey: PropertyKey.trainingDays)
}
override var description: String {
return """
Name: \(self.name)
Age: \(self.age)
Gender: \(self.gender)
Target: \(self.target)
Daily Meals: \(self.dailyMeals)
Does train?: \(self.isTraining)
When: \(self.trainingWhen ?? 0)
Days: \(self.trainingDays)
"""
}
func save() -> Bool {
return NSKeyedArchiver.archiveRootObject(self, toFile: Profile.path)
}
required init(coder unarchiver: NSCoder) {
super.init()
if let name = unarchiver.decodeObject(forKey: PropertyKey.name) as? String {
self.name = name
}
self.age = unarchiver.decodeInteger(forKey: PropertyKey.age)
self.gender = unarchiver.decodeInteger(forKey: PropertyKey.gender)
self.target = unarchiver.decodeInteger(forKey: PropertyKey.target)
self.dailyMeals = unarchiver.decodeInteger(forKey: PropertyKey.dailyMeals)
self.isTraining = unarchiver.decodeBool(forKey: PropertyKey.isTraining)
if let trainingWhen = unarchiver.decodeObject(forKey: PropertyKey.trainingWhen) as? Int {
self.trainingWhen = trainingWhen
}
if let trainingDays = unarchiver.decodeObject(forKey: PropertyKey.trainingDays) as? [Int] {
self.trainingDays = trainingDays
}
}
}
// TEST:
Profile.shared.name = "Daniel"
Profile.shared.age = 10
Profile.shared.gender = 30
Profile.shared.target = 10
Profile.shared.dailyMeals = 90
Profile.shared.isTraining = true
Profile.shared.trainingWhen = 20
Profile.shared.trainingDays = [1,2,5]
Profile.shared.save()
if let profile = NSKeyedUnarchiver.unarchiveObject(withFile: Profile.path) as? Profile {
print(profile.description)
}
/*
Output:
--------
Name: Daniel
Age: 10
Gender: 30
Target: 10
Daily Meals: 90
Does train?: true
When: 20
Days: [1, 2, 5]
*/