web-dev-qa-db-fra.com

Conversion d'un objet de classe personnalisé en NSData

J'ai une classe personnalisée que je souhaite enregistrer dans NSUserDefaults. On me dit que je dois convertir l'objet de classe en données afin de l'enregistrer dans NSUserDefaults. J'ai trouvé beaucoup de chaînes ou d'entiers discrets dans les exemples de NSData mais rien dans la classe personnalisée à NSData. Je connais très peu les subtilités de l'encodage NSData etc. Toute aide est appréciée

EDIT: Bien que je comprenne qu'il y a des réponses similaires ici, aucune d'entre elles n'est en Swift. La traduction entre les langues est faisable, mais elle est extrêmement fastidieuse et parfois très contre-intuitive.

22
Tamarisk

Voici un exemple simple pour vous:

//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
    }
}

Testé avec aire de jeux.

J'espère que cela t'aides.

37
Dharmesh

Cet exemple de code suivant est basé sur la réponse de Richie Rich (voir ci-dessus) et réussit les tests dans cet environnement:

  • 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

Ce lien peut vous aider

Il est important que votre classe étende NSObject et NSCoding, car la conversion doit être sa classe, NSCoding est une interface pour sérialiser et désérialiser votre classe

Enregistrement personnalisé Swift avec NSCoding vers UserDefaults

2
ViTUu