Подтвердить что ты не робот

Простое постоянное хранилище в Swift

У меня есть массив объектов, каждый из которых обладает рядом свойств. Вот несколько примеров данных, полученных путем циклического перемещения массива объектов:

Name = Rent
Default Value 750
This Months Estimate = 750
Sum Of This Months Actuals = 0
Risk Factor = 0.0
Monthly Average = 750.0
--------------
Name = Bills
Default Value 250
This Months Estimate = 170
Sum Of This Months Actuals = 140
Risk Factor = 0.0
Monthly Average = 190.0
--------------
Name = Food
Default Value 240
This Months Estimate = 200
Sum Of This Months Actuals = 95
Risk Factor = 0.0
Monthly Average = 190.0
--------------
Name = Lunches
Default Value 100
This Months Estimate = 150
Sum Of This Months Actuals = 155
Risk Factor = 0.899999976158142
Monthly Average = 190.0

Его очень маленькие данные, поэтому я хочу избежать использования основных данных. Мне нужно уметь сохранять массив, а затем открывать его снова и иметь возможность прокручивать его. Я надеялся использовать простое решение, такое как NSUserDefaults или NSKeyedArchiver, но в Swift я не могу ни работать с этим типом массива (через 24 часа я просматриваю документацию и форумы и примеры в Интернете...)

Как вы порекомендовали бы я сохранить сохранение массива объектов, как указано выше? ИЛИ, может быть, сохранить сохранение этого типа массива - это плохая практика?

Заранее благодарим за помощь!

Добавление класса объекта:

class costCategory : NSObject {
    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
    }

}

Если я попытаюсь сохранить массив в NSUserDefaults, я получаю ошибку:

Property list invalid for format: 200 (property lists cannot contain objects of type 'CFType')

Я попытался использовать наследование от класса NSCoder, но получаю сообщение об ошибке, которое Im не может решить, как показано ниже:

class costCategory : NSObject, NSCoder {
    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 convenience init(coder decoder: NSCoder) {
        self.init() //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")

    }

    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")

    }
}
4b9b3361

Ответ 1

Одна из возможностей заключается в преобразовании свойств объекта: значения в строку: объект сохраняют их до NSUserDefaults, а затем получают и декодируют их обратно.

Если вы хотите сохранить свой объект с помощью NSKeyedArchiver, ваш класс должен соответствовать NSCoding и быть подклассом NSObject. Пример:

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")

    }
}

Затем вы можете архивировать и сохранять в 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]

Ответ 2

Основные данные невероятно мощные, и я настоятельно рекомендую вам не пытаться поколебать его запугивающий внешний вид. Когда ваше приложение вырастет, вы будете невероятно благодарны за то, что вы сохранили свои данные с помощью Core Data, поскольку он масштабируется невероятно хорошо.

Это, как говорится, хорошая статья о NSHipster, которая охватывает основы использования NSKeyedArchiver. Таким образом, решение будет заключаться в том, чтобы ваши объекты были подклассом NSObject и соответствовали протоколу NSCoding. Это позволяет вам архивировать разрхивировать объекты с диска. Вы можете сохранить файл в каталоге документов.

Затем ваш подкласс должен будет неявно разворачивать все переменные, зависящие от кодирования, результат даст:

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")
}
}

Затем вы можете добавить способ нахождения местоположения в каталоге документов:

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

Итак, архивирование будет выглядеть так:

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

а затем вы можете прочитать свой массив с диска:

let receipts = NSKeyedUnarchiver.unarchiveObjectWithFile(filePath)

Я бы порекомендовал против использования пользовательских настроек по умолчанию для хранения массива, предназначенных для сохранения предпочтений, здесь взгляните на документацию:

Класс NSUserDefaults предоставляет программный интерфейс для взаимодействуя с системой по умолчанию. Система по умолчанию позволяет приложение, чтобы настроить его поведение в соответствии с предпочтениями пользователей. Например, вы можете разрешить пользователям определять, какие единицы измерения вашего приложения или того, как часто документы автоматически сохраняется. Приложения записывают такие предпочтения, присваивая значения к набору параметров в базе данных по умолчанию пользователей.

В идеале вы не хотите сохранять массивы, потому что тогда вам нужно извлечь весь массив в память, даже если вам нужен один объект. Естественно, основные данные будут решать все ненужные беспорядки для вас:)

ИЗМЕНИТЬ

Чтобы облегчить себя в Core Data, вы всегда можете посмотреть Magical Record. Они упрощают большую часть трещины, необходимой для поддержания стека основных данных.

Удача

Евангелист основных данных