How to save an array of objects to NSUserDefault with swift?
Swift 4
We need to serialize our swift
object to save it into userDefaults
.
In swift 4 we can use Codable protocol, which makes our life easy on serialization and JSON parsing
Workflow(Save swift object in UserDefaults):
- Confirm Codable protocol to model class(class Place : Codable).
- Create object of class.
- Serialize that class using JsonEncoder class.
- Save serialized(Data) object to UserDefaults.
Workflow(Get swift object from UserDefaults):
- Get data from UserDefaults(Which will return Serialized(Data) object)
- Decode Data using JsonDecoder class
Swift 4 Code:
class Place: Codable { var latitude: Double var longitude: Double init(lat : Double, long: Double) { self.latitude = lat self.longitude = long } public static func savePlaces(){ var placeArray = [Place]() let place1 = Place(lat: 10.0, long: 12.0) let place2 = Place(lat: 5.0, long: 6.7) let place3 = Place(lat: 4.3, long: 6.7) placeArray.append(place1) placeArray.append(place2) placeArray.append(place3) let placesData = try! JSONEncoder().encode(placeArray) UserDefaults.standard.set(placesData, forKey: "places") } public static func getPlaces() -> [Place]?{ let placeData = UserDefaults.standard.data(forKey: "places") let placeArray = try! JSONDecoder().decode([Place].self, from: placeData!) return placeArray }}
From the Property List Programming Guide:
If a property-list object is a container (that is, an array or dictionary), all objects contained within it must also be property-list objects. If an array or dictionary contains objects that are not property-list objects, then you cannot save and restore the hierarchy of data using the various property-list methods and functions.
You'll need to convert the object to and from an NSData
instance using NSKeyedArchiver
and NSKeyedUnarchiver
.
For example:
func savePlaces(){ let placesArray = [Place(lat: 123, lng: 123, name: "hi")] let placesData = NSKeyedArchiver.archivedDataWithRootObject(placesArray) NSUserDefaults.standardUserDefaults().setObject(placesData, forKey: "places")}func loadPlaces(){ let placesData = NSUserDefaults.standardUserDefaults().objectForKey("places") as? NSData if let placesData = placesData { let placesArray = NSKeyedUnarchiver.unarchiveObjectWithData(placesData) as? [Place] if let placesArray = placesArray { // do something… } }}
Swift 3 & 4
The following is the complete example code in Swift 3 & 4.
import Foundationclass Place: NSObject, NSCoding { var latitude: Double var longitude: Double var name: String init(latitude: Double, longitude: Double, name: String) { self.latitude = latitude self.longitude = longitude self.name = name } required init?(coder aDecoder: NSCoder) { self.latitude = aDecoder.decodeDouble(forKey: "latitude") self.longitude = aDecoder.decodeDouble(forKey: "longitude") self.name = aDecoder.decodeObject(forKey: "name") as? String ?? "" } func encode(with aCoder: NSCoder) { aCoder.encode(latitude, forKey: "latitude") aCoder.encode(longitude, forKey: "longitude") aCoder.encode(name, forKey: "name") }}func savePlaces() { var placesArray: [Place] = [] placesArray.append(Place(latitude: 12, longitude: 21, name: "place 1")) placesArray.append(Place(latitude: 23, longitude: 32, name: "place 2")) placesArray.append(Place(latitude: 34, longitude: 43, name: "place 3")) let placesData = NSKeyedArchiver.archivedData(withRootObject: placesArray) UserDefaults.standard.set(placesData, forKey: "places")}func loadPlaces() { guard let placesData = UserDefaults.standard.object(forKey: "places") as? NSData else { print("'places' not found in UserDefaults") return } guard let placesArray = NSKeyedUnarchiver.unarchiveObject(with: placesData as Data) as? [Place] else { print("Could not unarchive from placesData") return } for place in placesArray { print("") print("place.latitude: \(place.latitude)") print("place.longitude: \(place.longitude)") print("place.name: \(place.name)") }}
Example Use:
savePlaces()loadPlaces()
Console Output:
place.latitude: 12.0place.longitude: 21.0place.name: 'place 1'place.latitude: 23.0place.longitude: 32.0place.name: 'place 2'place.latitude: 34.0place.longitude: 43.0place.name: 'place 3'