web-dev-qa-db-ja.com

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時間数...)

上記のようなオブジェクトの配列を永続的に保存することをどのように勧めますか? OR多分このタイプの配列を保存し続けることは悪い習慣ですか?

よろしくお願いします!

オブジェクトクラスの追加:

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

    }
}
15
user3535074

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]
31
Kirsteins

Core Dataは信じられないほど強力であり、その威圧的な外観に左右されないようにしてください。アプリが大きくなると、Core Dataが信じられないほどスケーラブルにデータをバックアップしたことを信じられないほど感謝します。

そうは言っても、 NSKeyedArchiverの使用の基本をカバーするNSHipster に関する素晴らしい記事があります。したがって、解決策は、オブジェクトを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クラスは、デフォルトシステムと対話するためのプログラムインターフェイスを提供します。デフォルトのシステムでは、ユーザーの好みに合わせてアプリケーションで動作をカスタマイズできます。たとえば、アプリケーションが表示する測定単位やドキュメントが自動的に保存される頻度をユーザーが決定できるようにすることができます。アプリケーションは、ユーザーのデフォルトデータベースのパラメータセットに値を割り当てることにより、このような設定を記録します。

1つのオブジェクトが必要な場合でも、配列全体をメモリにフェッチする必要があるため、理想的には配列を永続化したくない。当然、コアデータは、不要なヒープの混乱をすべて解決します。

[〜#〜]編集[〜#〜]

Core Dataに慣れるために、常に Magical Record を見ることができます。それらは、コアデータスタックを維持するために必要な多くの残骸を簡素化します。

幸運を

コアデータエバンジェリスト

6
Daniel Galasko