Simple persistent storage in Swift

前端 未结 2 651
野的像风
野的像风 2020-12-09 17:34

I have an array of objects each with a number of properties. Here is some sample data taken by looping through the array of objects:

Name = Rent
Default Valu         


        
相关标签:
2条回答
  • 2020-12-09 17:57

    One possibility is to convert your object properties:values to string:object store them to NSUserDefaults and then get and decode them back.

    If you want to store your object using NSKeyedArchiver, your class needs to conform to NSCoding and be subclass of NSObject. Example:

    class costCategory : NSObject, NSCoding {
        var name : String
        var defaultValue : Int
        var thisMonthsEstimate : Int
        var sumOfThisMonthsActuals : Int
        var riskFactor : Float
        var monthlyAverage : Float
    
        init (name:String, defaultValue:Int, thisMonthsEstimate:Int, sumOfThisMonthsActuals:Int, riskFactor:Float, monthlyAverage:Float) {
            self.name = name
            self.defaultValue = defaultValue
            self.thisMonthsEstimate = thisMonthsEstimate
            self.sumOfThisMonthsActuals = sumOfThisMonthsActuals
            self.riskFactor = riskFactor
            self.monthlyAverage = monthlyAverage
        }
    
        // MARK: NSCoding
    
        required init(coder decoder: NSCoder) {
            //Error here "missing argument for parameter name in call
            self.name = decoder.decodeObjectForKey("name") as String
            self.defaultValue = decoder.decodeIntegerForKey("defaultValue")
            self.thisMonthsEstimate = decoder.decodeIntegerForKey("thisMonthsEstimate")
            self.sumOfThisMonthsActuals = decoder.decodeIntegerForKey("sumOfThisMonthsActuals")
            self.riskFactor = decoder.decodeFloatForKey("riskFactor")
            self.monthlyAverage = decoder.decodeFloatForKey("monthlyAverage")
            super.init()
        }
    
        func encodeWithCoder(coder: NSCoder) {
            coder.encodeObject(self.name, forKey: "name")
            coder.encodeInt(Int32(self.defaultValue), forKey: "defaultValue")
            coder.encodeInt(Int32(self.thisMonthsEstimate), forKey: "thisMonthsEstimate")
            coder.encodeInt(Int32(self.sumOfThisMonthsActuals), forKey: "sumOfThisMonthsActuals")
            coder.encodeFloat(self.riskFactor, forKey: "riskFactor")
            coder.encodeFloat(self.monthlyAverage, forKey: "monthlyAverage")
    
        }
    }
    

    Then you can archive and save to NSDefaults:

    let defaults = NSUserDefaults.standardUserDefaults()
    let arrayOfObjectsKey = "arrayOfObjectsKey"
    
    var arrayOfObjects = [costCategory]()
    var arrayOfObjectsData = NSKeyedArchiver.archivedDataWithRootObject(arrayOfObjects)
    
    defaults.setObject(arrayOfObjectsData, forKey: arrayOfObjectsKey)
    
    // ...
    
    var arrayOfObjectsUnarchivedData = defaults.dataForKey(arrayOfObjectsKey)!
    var arrayOfObjectsUnarchived = NSKeyedUnarchiver.unarchiveObjectWithData(arrayOfObjectsUnarchivedData) as [costCategory]
    
    0 讨论(0)
  • 2020-12-09 18:08

    Core Data is incredibly powerful and I highly recommend you try not be swayed by its intimidating appearance. When your app grows you will be incredibly grateful that you backed your data with Core Data as it scales incredibly well.

    That being said, theres a nice article on NSHipster that covers the basics of using the NSKeyedArchiver. So the solution would be to have your objects be a subclass of NSObject and conform to the NSCoding protocol. This allows you to archive an unarchive the objects from the disk. You can the save your file to the documents directory

    Your subclass would then need to implicitly unwrap all the encode-able variables, the result would yield:

    class costCategory : NSObject, NSCoding {
    var name : String!
    var defaultValue : Int!
    var thisMonthsEstimate : Int!
    var sumOfThisMonthsActuals : Int!
    var riskFactor : Float!
    var monthlyAverage : Float!
    
    
    init (name:String, defaultValue:Int, thisMonthsEstimate:Int, sumOfThisMonthsActuals:Int, riskFactor:Float, monthlyAverage:Float) {
        self.name = name
        self.defaultValue = defaultValue
        self.thisMonthsEstimate = thisMonthsEstimate
        self.sumOfThisMonthsActuals = sumOfThisMonthsActuals
        self.riskFactor = riskFactor
        self.monthlyAverage = monthlyAverage
    }
    
    override init() {
        super.init()
    }
    
    // MARK: NSCoding
    
    required convenience init(coder decoder: NSCoder) {
        self.init()
        self.name = decoder.decodeObjectForKey("name") as String
        self.defaultValue = decoder.decodeIntegerForKey("defaultValue")
        self.thisMonthsEstimate = decoder.decodeIntegerForKey("thisMonthsEstimate")
        self.sumOfThisMonthsActuals = decoder.decodeIntegerForKey("sumOfThisMonthsActuals")
        self.riskFactor = decoder.decodeFloatForKey("riskFactor")
        self.monthlyAverage = decoder.decodeFloatForKey("monthlyAverage")
    }
    
    func encodeWithCoder(coder: NSCoder) {
        coder.encodeObject(self.name, forKey: "name")
        coder.encodeInteger((self.defaultValue), forKey: "defaultValue")
        coder.encodeInteger((self.thisMonthsEstimate), forKey: "thisMonthsEstimate")
        coder.encodeInteger((self.sumOfThisMonthsActuals), forKey: "sumOfThisMonthsActuals")
        coder.encodeFloat(self.riskFactor, forKey: "riskFactor")
        coder.encodeFloat(self.monthlyAverage, forKey: "monthlyAverage")
    }
    }
    

    You could then add a way of finding the location to the documents directory:

    func documentsDirectory() -> NSString {
        let paths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)
        let documentDirectory = paths[0] as String
        return documentDirectory
    }
    

    So archiving would look like this:

    var filePath = documentsDirectory().stringByAppendingPathComponent("fileName")
    NSKeyedArchiver.archiveRootObject(receipts, toFile: filePath)
    

    and later on you could read your array back from disk:

    let receipts = NSKeyedUnarchiver.unarchiveObjectWithFile(filePath)
    

    I would recommend against using User Defaults to store an array, its meant to store preferences, here take a look at the documentation:

    The NSUserDefaults class provides a programmatic interface for interacting with the defaults system. The defaults system allows an application to customize its behavior to match a user’s preferences. For example, you can allow users to determine what units of measurement your application displays or how often documents are automatically saved. Applications record such preferences by assigning values to a set of parameters in a user’s defaults database.

    Ideally you don't want to persist arrays because then you have to fetch the entire array into memory even if you need one object. Naturally Core Data will solve all that unnecessary heap mess for you:)

    EDIT

    To ease yourself into Core Data you could always look at Magical Record. They simplify a lot of the cruft needed to maintain the Core Data stack.

    Good Luck

    Core Data Evangelist

    0 讨论(0)
提交回复
热议问题