Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to save an array of objects to NSUserDefault with swift?

this is a class Place I defined:

class Place: NSObject {      var latitude: Double     var longitude: Double      init(lat: Double, lng: Double, name: String){         self.latitude = lat         self.longitude = lng     }      required init(coder aDecoder: NSCoder) {         self.latitude = aDecoder.decodeDoubleForKey("latitude")         self.longitude = aDecoder.decodeDoubleForKey("longitude")     }      func encodeWithCoder(aCoder: NSCoder!) {         aCoder.encodeObject(latitude, forKey: "latitude")         aCoder.encodeObject(longitude, forKey: "longitude")     }  } 

This is how I tried to save an array of Places:

var placesArray = [Place]  //...  func savePlaces() {     NSUserDefaults.standardUserDefaults().setObject(placesArray, forKey: "places")     println("place saved") } 

It didn't work, this is what I get on the console:

Property list invalid for format: 200 (property lists cannot contain objects of type 'CFType') 

I am new to iOS, could you help me ?

SECOND EDITION

I found a solution to save the data :

func savePlaces(){     let myData = NSKeyedArchiver.archivedDataWithRootObject(placesArray)    NSUserDefaults.standardUserDefaults().setObject(myData, forKey: "places")     println("place saved") } 

But I get an error when loading the data with this code :

 let placesData = NSUserDefaults.standardUserDefaults().objectForKey("places") as? NSData   if placesData != nil {       placesArray = NSKeyedUnarchiver.unarchiveObjectWithData(placesData!) as [Place]  } 

the error is :

[NSKeyedUnarchiver decodeDoubleForKey:]: value for key (latitude) is not a double number' 

I am pretty sure I archived a Double, there is an issue with the saving/loading process

Any clue ?

like image 206
Cherif Avatar asked Jan 30 '15 16:01

Cherif


People also ask

How do I save an array of objects in Swift?

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.

How do you save a Userdefault string in Swift?

To store the string in the user's defaults database, which is nothing more than a property list or plist, we pass the string to the set(_:forKey:) method of the UserDefaults class. We also need to pass a key as the second argument to the set(_:forKey:) method because we are creating a key-value pair.


2 Answers

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):

  1. Confirm Codable protocol to model class(class Place : Codable).
  2. Create object of class.
  3. Serialize that class using JsonEncoder class.
  4. Save serialized(Data) object to UserDefaults.

Workflow(Get swift object from UserDefaults):

  1. Get data from UserDefaults(Which will return Serialized(Data) object)
  2. 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     } } 
like image 154
Kazi Abdullah Al Mamun Avatar answered Sep 29 '22 12:09

Kazi Abdullah Al Mamun


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…         }      } } 
like image 30
Aaron Brager Avatar answered Sep 29 '22 14:09

Aaron Brager