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 NSUserDefaults
. I found a lot of discrete string or ints to NSData
examples but nothing on custom class to NSData
. I know very little about the intricacies of NSData
encoding etc. Any help is appreciated
EDIT: While I understand there are similar answers here, none of them are in Swift. Translating between the languages is doable, but it is extremely tedious and sometimes very counter-intuitive.
Here is one simple example for you:
//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
}
}
Tested with playground.
Hope this helps.
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
}
This link can help you
It is important your class extend NSObject
and NSCoding
, because the convert need be its class, NSCoding
is an interface to serialize and deserialize your class
Saving custom SWIFT class with NSCoding to UserDefaults
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With