web-dev-qa-db-ja.com

カスタムクラスオブジェクトをNSDataに変換する

NSUserDefaultsに保存するカスタムクラスがあります。 NSUserDefaultsに保存するには、クラスオブジェクトをデータに変換する必要があると言われています。 NSDataの例に対する多くの個別の文字列またはintを見つけましたが、NSDataのカスタムクラスには何も見つかりませんでした。 NSDataエンコーディングなどの複雑さについてはほとんど知りません。

編集:ここには同様の答えがあると理解していますが、Swiftにはありません。言語間の翻訳は実行可能ですが、非常に退屈で、時には非常に直感に反します。

22
Tamarisk

簡単な例を次に示します。

//Custom class.
class Person: NSObject, NSCoding {
    var name: String!
    var age: Int!
    required convenience init(coder decoder: NSCoder) {
        self.init()
        self.name = decoder.decodeObjectForKey("name") as! String
        self.age = decoder.decodeObjectForKey("age") as! Int
    }
    convenience init(name: String, age: Int) {
        self.init()
        self.name = name
        self.age = age
    }
    func encodeWithCoder(coder: NSCoder) {
        if let name = name { coder.encodeObject(name, forKey: "name") }
        if let age = age { coder.encodeObject(age, forKey: "age") }

    }
}

//create an instance of your custom class.
var newPerson = [Person]()

//add some values into custom class.
newPerson.append(Person(name: "Leo", age: 45))
newPerson.append(Person(name: "Dharmesh", age: 25))

//store you class object into NSUserDefaults.
let personData = NSKeyedArchiver.archivedDataWithRootObject(newPerson)
NSUserDefaults().setObject(personData, forKey: "personData")


//get your object from NSUserDefaults.
if let loadedData = NSUserDefaults().dataForKey("personData") {

    if let loadedPerson = NSKeyedUnarchiver.unarchiveObjectWithData(loadedData) as? [Person] {
        loadedPerson[0].name   //"Leo"
        loadedPerson[0].age    //45
    }
}

遊び場でテスト済み。

お役に立てれば。

37
Dharmesh

次のサンプルコードは、Richie Richの回答(上記を参照)に基づいており、この環境でテストに合格します。

  • Xcode version 9.1 (9B55)
  • Swift version 4.0.2 (swiftlang-900.0.69.2 clang-900.0.38, Target: x86_64-Apple-macosx10.9)
  • MacBook Air (11-inch, Mid 2012) with macOS High Sierra (version 10.13.1)

// Foundation is required to NSObject and NSCoding
import Foundation

// A custom class called Person with two properties (a string name and an
// integer age), that is a subclass of NSObject and adopts NSCoding protocol.
class Person: NSObject, NSCoding {
  var name: String!
  var age: Int!

  // The convenience initializer for class Person
  // Reference
  // https://developer.Apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Initialization.html#//Apple_ref/doc/uid/TP40014097-CH18-ID217
  convenience init(name: String, age: Int) {
    // self.init() is the designated initializer for class Person.
    // Reference
    // https://developer.Apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Initialization.html#//Apple_ref/doc/uid/TP40014097-CH18-ID219
    self.init()
    self.name = name
    self.age = age
  }

  // The initializer init(coder:) is required by NSCoding protocol
  // Reference
  // https://developer.Apple.com/documentation/foundation/nscoding
  // https://developer.Apple.com/documentation/foundation/nscoding/1416145-init
  required convenience init(coder aDecoder: NSCoder) {
    self.init()
    // as! is a type casting operator
    // Reference
    // https://developer.Apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//Apple_ref/doc/uid/TP40014097-CH32-ID388
    self.name = aDecoder.decodeObject(forKey: "name") as! String
    self.age = aDecoder.decodeInteger(forKey: "age")
  }

  // The instance method encode(with:) is required by NSCoding protocol
  // Reference
  // https://developer.Apple.com/documentation/foundation/nscoding
  // https://developer.Apple.com/documentation/foundation/nscoding/1413933-encode
  func encode(with anEncoder: NSCoder) {
    if let name = name {
      anEncoder.encode(name, forKey: "name")
    }
    if let age = age {
      anEncoder.encode(age, forKey: "age")
    }
  }
}

// Create an array (or, generally speaking, a collection) as a container to
// hold instances of our custom class type Person.
// Reference
// https://developer.Apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/CollectionTypes.html
var anArrayOfPersons = [Person]()
print(anArrayOfPersons.count) // 0

// Add two instances into anArrayOfPersons.
// Reference
// https://developer.Apple.com/documentation/Swift/array
// https://developer.Apple.com/documentation/Swift/array/1538872-append
anArrayOfPersons.append(Person(name: "Cong", age: 33))
anArrayOfPersons.append(Person(name: "Sunny", age: 2))

// Archive anArrayOfPersons into NSData using NSKeyedArchiver.
// Reference
// https://developer.Apple.com/documentation/foundation/nskeyedarchiver
// https://developer.Apple.com/documentation/foundation/nskeyedarchiver/1413189-archiveddata
let dataToSave = NSKeyedArchiver.archivedData(withRootObject: anArrayOfPersons)

// Persist data. Storing anArrayOfPersons into UserDefaults as data.
// Reference
// https://developer.Apple.com/documentation/foundation/userdefaults
// https://developer.Apple.com/documentation/foundation/userdefaults/1414067-set
UserDefaults().set(dataToSave, forKey: "tagOfData")

// Take our stored data (in previous step) from UserDefaults using the key
// "personData". Optional binding is used to make sure the retrieved data is
// not nil.
// Reference
// https://developer.Apple.com/documentation/foundation/userdefaults
// https://developer.Apple.com/documentation/foundation/userdefaults/1409590-data
// https://developer.Apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/TheBasics.html#//Apple_ref/doc/uid/TP40014097-CH5-ID333
if let dataRetrieved = UserDefaults().data(forKey: "tagOfData"),
  // Decode our instance objects from the retrieved data
  // Reference
  // https://developer.Apple.com/documentation/foundation/nskeyedunarchiver
  // https://developer.Apple.com/documentation/foundation/nskeyedunarchiver/1413894-unarchiveobject
  let anArrayOfPersonsRetrieved = NSKeyedUnarchiver.unarchiveObject(with: dataRetrieved) as? [Person] {
    // See how many bytes the data we retrieved has.
    print(dataRetrieved) // 393 bytes

    // See if the name and age properties are the same as what we stored.
    print(anArrayOfPersonsRetrieved[0].name) // "Cong"
    print(anArrayOfPersonsRetrieved[0].age)  // 45
    print(anArrayOfPersonsRetrieved[1].name) // "Sunny"
    print(anArrayOfPersonsRetrieved[1].age)  // 2
  }
5
George

このリンクはあなたを助けることができます

NSObjectNSCodingをクラスで拡張することが重要です。変換はそのクラスである必要があるため、NSCodingはクラスをシリアライズおよびデシリアライズするためのインターフェースです

Save Custom Swift NSCoding with UserDefaultsのクラス

2
ViTUu