将自定义 class 对象转换为 NSData

Converting custom class object into NSData

我有一个自定义 class,我想将其保存到 NSUserDefaults。我被告知我需要将 class 对象转换为数据以便将其保存到 NSUserDefaults。我发现了很多离散字符串或整数到 NSData 的例子,但没有关于自定义 class 到 NSData 的例子。我对 NSData 编码等的复杂性知之甚少。感谢任何帮助

编辑:虽然我知道这里有类似的答案,但其中 none 在 Swift 中。语言之间的翻译是可行的,但它非常乏味,有时甚至非常违反直觉。

这里有一个简单的例子供您参考:

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

已在 playground 上测试。

希望对您有所帮助。

这个link可以帮到你

重要的是你的 class 扩展 NSObjectNSCoding,因为转换需要是它的 class,NSCoding 是一个接口来序列化和反序列化你的 class

Saving custom SWIFT class with NSCoding to UserDefaults

以下示例代码基于 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
  }