简体   繁体   中英

Unable to retrieve saved array of custom Swift objects

I'm creating a quick app that tracks user purchases in Swift. There's a Purchase class, and I'm trying to save an NSMutableArray of these to the user defaults.

When I go to load the data, after first pressing quitting the app to trigger a save, the else is always ran. Retrieving the integer amount (the data for KEY_WEEKLY_AMOUNT) is always successful though.

class UserDatas {
static let sharedInstance = UserDatas()
let defaults = NSUserDefaults.standardUserDefaults()
let KEY_ARRAY_OF_PURCHASES = "KEY_ARRAY_OF_PURCHASES"
let KEY_WEEKLY_AMOUNT = "KEY_WEEKLY_AMOUNT"

var arrayOfUserPurchases:NSMutableArray = NSMutableArray()
var weeklyAmount:Int = 0


func saveTheDatas() {

    let arrayOfArchivedDatas = NSKeyedArchiver.archivedDataWithRootObject(arrayOfUserPurchases)
    defaults.setObject(arrayOfArchivedDatas, forKey: KEY_ARRAY_OF_PURCHASES)

    defaults.setInteger(weeklyAmount, forKey: KEY_WEEKLY_AMOUNT)

    print("Saved data.")
}

func loadTheDatas() {
    if let decodedNSDataBlob = defaults.objectForKey(KEY_ARRAY_OF_PURCHASES) as? NSData {
        if let unarchivedArray = NSKeyedUnarchiver.unarchiveObjectWithData(decodedNSDataBlob) as? NSArray {

            self.arrayOfUserPurchases = NSMutableArray.init(array: unarchivedArray)
        }
    } else {

        // THIS ALWAYS HAPPENS. //

        print("No Purchases yet! Initializing with blank array.")
        arrayOfUserPurchases = NSMutableArray()
        return
    }

    let savedWeeklyAmount = defaults.integerForKey(KEY_WEEKLY_AMOUNT)
    self.weeklyAmount = savedWeeklyAmount
    print("Loaded saved weekly amount: \(savedWeeklyAmount).")

}

And the Purchase class:

class Purchase : NSObject, NSCoding {

let KEY_PURCHASE_AMOUNT = "PURCHASE_AMOUNT"
let KEY_PURCHASE_CATEGORY = "PURCHASE_CATEGORY"
let KEY_PURCHASE_TIME = "PURCHASE_TIME"
let KEY_PURCHASE_DATE = "PURCHASE_DATE"

var amount:Int = 0
var time:String = ""
var date:String = ""
var category:Int = 0
var valid:Bool = false

init(amount:Int, time:String, date:String, category:Int) {
    self.amount = amount
    self.time = time
    self.date = date
    self.category = category
    self.valid = true
}

override init() {
    self.valid = false
}

// MARK: NSCoding
required convenience init?(coder aDecoder: NSCoder) {

    guard let amount = aDecoder.decodeObjectForKey("amount") as? Int
        else {
            self.init()
            return
        }
    guard let time = aDecoder.decodeObjectForKey("time") as? String
        else {
            self.init()
            return
    }
    guard let date = aDecoder.decodeObjectForKey("date") as? String
        else {
            self.init()
            return
    }
    guard let category = aDecoder.decodeObjectForKey("category") as? Int
        else {
            self.init()
            return
    }
    guard let valid = aDecoder.decodeObjectForKey("valid") as? Bool
        else {
            self.init()
            return
    }

    self.init(amount: amount, time: time, date: date, category: category)
}



func encodeWithCoder(aCoder: NSCoder) {
    aCoder.encodeInt(Int32(self.amount), forKey: "amount")
    aCoder.encodeObject(self.time, forKey: "time")
    aCoder.encodeObject(self.date, forKey: "date")
    aCoder.encodeInt(Int32(self.category), forKey: "category")
    aCoder.encodeBool(self.valid, forKey: "valid")
} 

}

Your Purchase class needs following improvements

Instead of using a guard statement use if let like

if let amount = aDecoder.decodeObjectForKey("amount") as? Int
{
        self.amount = amount
}

Forget about your init calls inside initWithCoder, It is already initializing your object, so you don't need to init again

Also try to save your data using encodeObject like

aCoder.encodeObject(amount, forKey: "amount")

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM