NSKeyedUnarchiver无法解码我的一些密钥

时间:2017-06-24 22:25:27

标签: swift nskeyedarchiver

我有一些我想要解码的键,但它只解码我的第一个字符串然后它会出错。

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,我完全不知道为什么会发生这种情况,因为我可以在代码中看到它进行编码。 :/

1 个答案:

答案 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]

*/