如何使用swift将对象数组保存到NSUserDefault?

这是一个我定义的Place

 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") } } 

这是我试图保存一个Place的数组:

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

它没有工作,这是我在控制台上得到的:

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

我是iOS新手,你能帮我吗?

第二版

我find了一个解决scheme来保存数据:

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

但是当用这个代码加载数据时,我得到一个错误:

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

错误是:

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

我很确定我存档了一个Double,存在一个与保存/加载过程有关的问题

任何线索?

从Property List编程指南 :

如果属性列表对象是一个容器(即数组或字典),则其中包含的所有对象也必须是属性列表对象。 如果数组或字典中包含的对象不是属性列表对象,则不能使用各种属性列表方法和函数保存和还原数据的层次结构。

您需要使用NSKeyedArchiverNSKeyedUnarchiver将对象转换为NSData实例。

例如:

 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

以下是Swift 3和4中的完整示例代码。

 import Foundation class 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)") } } 

使用示例:

 savePlaces() loadPlaces() 

控制台输出:

 place.latitude: 12.0 place.longitude: 21.0 place.name: 'place 1' place.latitude: 23.0 place.longitude: 32.0 place.name: 'place 2' place.latitude: 34.0 place.longitude: 43.0 place.name: 'place 3' 

您已经准备好归档的位置,但是现在假设您将一个Place数组自动存档到NSUserDefaults中。 不会的 必须将其归档。 错误信息告诉你这一点。 唯一可以保存在NSUserDefaults中的东西是具有属性列表types的对象:NSArray,NSDictionary,NSString,NSData,NSDate和NSNumber。 Place对象不是其中之一。

而不是直接保存数组,将其归档 。 现在它是一个NSData – 这是属性列表对象types之一:

 let myData = NSKeyedArchiver.archivedDataWithRootObject(placesArray) 

现在你可以将myData存储在NSUserDefaults中,因为它是一个NSData。 当然,当你把它拉出来,你也必须unarchive它把它从一个NSData返回到一个地方的数组。

编辑 :顺便说一下,作为一个事后,它发生在我的地方类可能不得不明确采用NSCoding协议得到这个工作。 你似乎已经省略了这一步。