I have a custom class that I want to save into NSUserDefaults
. I am told that I need to convert the class object into data in order to save it to NSUserDefaul
This following sample code is based on Richie Rich's answer (see above) and passes tests in this environment:
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
}