尝试将非属性列表对象设置为NSUserDefaults
我以为我知道是什么导致了这个错误,但我似乎无法弄清楚我做错了什么。
这是我得到的完整的错误消息:
尝试设置一个非属性列表对象( “<BC_Person:0x8f3c140>” )作为关键personDataArray的NSUserDefaults值
我有一个Person
类,我认为是符合NSCoding
协议,我在这个人类中有这两种方法:
- (void)encodeWithCoder:(NSCoder *)coder { [coder encodeObject:self.personsName forKey:@"BCPersonsName"]; [coder encodeObject:self.personsBills forKey:@"BCPersonsBillsArray"]; } - (id)initWithCoder:(NSCoder *)coder { self = [super init]; if (self) { self.personsName = [coder decodeObjectForKey:@"BCPersonsName"]; self.personsBills = [coder decodeObjectForKey:@"BCPersonsBillsArray"]; } return self; }
在应用程序的某个时刻, BC_PersonClass
的NSString
被设置,并且我有一个DataSave
类,我认为它正在处理BC_PersonClass
的属性的编码。 这里是我从DataSave
类使用的代码:
- (void)savePersonArrayData:(BC_Person *)personObject { // NSLog(@"name of the person %@", personObject.personsName); [mutableDataArray addObject:personObject]; // set the temp array to the mutableData array tempMuteArray = [NSMutableArray arrayWithArray:mutableDataArray]; // save the person object as nsData NSData *personEncodedObject = [NSKeyedArchiver archivedDataWithRootObject:personObject]; // first add the person object to the mutable array [tempMuteArray addObject:personEncodedObject]; // NSLog(@"Objects in the array %lu", (unsigned long)mutableDataArray.count); // now we set that data array to the mutable array for saving dataArray = [[NSArray alloc] initWithArray:mutableDataArray]; //dataArray = [NSArray arrayWithArray:mutableDataArray]; // save the object to NS User Defaults NSUserDefaults *userData = [NSUserDefaults standardUserDefaults]; [userData setObject:dataArray forKey:@"personDataArray"]; [userData synchronize]; }
我希望这是足够的代码给你一个想法,我正在尝试做什么。 我再次知道我的问题在于如何在我的BC_Person类中编码我的属性,我似乎无法弄清楚我做错了什么。
谢谢您的帮助!
您发布的代码尝试将自定义对象的数组保存到NSUserDefaults
。 你不能这样做。 实现NSCoding
方法并没有帮助。 你只能在NSUserDefaults
存储NSArray
, NSDictionary
, NSString
, NSData
, NSNumber
和NSDate
。
你需要将对象转换为NSData
(就像你在一些代码中)并将NSData
存储在NSUserDefaults
。 你甚至可以存储一个NSData
的NSArray
,如果你需要的话。
当您读回数组时,您需要取消存档NSData
以取回您的BC_Person
对象。
也许你想这样做:
- (void)savePersonArrayData:(BC_Person *)personObject { [mutableDataArray addObject:personObject]; NSMutableArray *archiveArray = [NSMutableArray arrayWithCapacity:mutableDataArray.count]; for (BC_Person *personObject in mutableDataArray) { NSData *personEncodedObject = [NSKeyedArchiver archivedDataWithRootObject:personObject]; [archiveArray addObject:personEncodedObject]; } NSUserDefaults *userData = [NSUserDefaults standardUserDefaults]; [userData setObject:archiveArray forKey:@"personDataArray"]; }
对我来说,运行数组并将其编码到NSData中似乎相当浪费。 你的错误BC_Person is a non-property-list object
告诉你,框架不知道如何序列化你的人物。
所以所需要的只是确保你的person对象符合NSCoding,然后你可以简单地将你的自定义对象数组转换成NSData并将其存储为默认值。 下面是一个操场:
编辑 :编写NSUserDefaults
在Xcode 7上打破,所以操场将归档到数据并返回并打印输出。 UserDefaults步骤包含在稍后修复的情况下
//: Playground - noun: a place where people can play import Foundation class Person: NSObject, NSCoding { let surname: String let firstname: String required init(firstname:String, surname:String) { self.firstname = firstname self.surname = surname super.init() } //MARK: - NSCoding - required init(coder aDecoder: NSCoder) { surname = aDecoder.decodeObjectForKey("surname") as! String firstname = aDecoder.decodeObjectForKey("firstname") as! String } func encodeWithCoder(aCoder: NSCoder) { aCoder.encodeObject(firstname, forKey: "firstname") aCoder.encodeObject(surname, forKey: "surname") } } //: ### Now lets define a function to convert our array to NSData func archivePeople(people:[Person]) -> NSData { let archivedObject = NSKeyedArchiver.archivedDataWithRootObject(people as NSArray) return archivedObject } //: ### Create some people let people = [Person(firstname: "johnny", surname:"appleseed"),Person(firstname: "peter", surname: "mill")] //: ### Archive our people to NSData let peopleData = archivePeople(people) if let unarchivedPeople = NSKeyedUnarchiver.unarchiveObjectWithData(peopleData) as? [Person] { for person in unarchivedPeople { print("\(person.firstname), you have been unarchived") } } else { print("Failed to unarchive people") } //: ### Lets try use NSUserDefaults let UserDefaultsPeopleKey = "peoplekey" func savePeople(people:[Person]) { let archivedObject = archivePeople(people) let defaults = NSUserDefaults.standardUserDefaults() defaults.setObject(archivedObject, forKey: UserDefaultsPeopleKey) defaults.synchronize() } func retrievePeople() -> [Person]? { if let unarchivedObject = NSUserDefaults.standardUserDefaults().objectForKey(UserDefaultsPeopleKey) as? NSData { return NSKeyedUnarchiver.unarchiveObjectWithData(unarchivedObject) as? [Person] } return nil } if let retrievedPeople = retrievePeople() { for person in retrievedPeople { print("\(person.firstname), you have been unarchived") } } else { print("Writing to UserDefaults is still broken in playgrounds") }
而瞧,你已经将自定义对象的数组存储到NSUserDefaults中
保存:
NSUserDefaults *currentDefaults = [NSUserDefaults standardUserDefaults]; NSData *data = [NSKeyedArchiver archivedDataWithRootObject:yourObject]; [currentDefaults setObject:data forKey:@"yourKeyName"];
要得到:
NSData *data = [currentDefaults objectForKey:@"yourKeyName"]; yourObjectType * token = [NSKeyedUnarchiver unarchiveObjectWithData:data];
删除
[currentDefaults removeObjectForKey:@"yourKeyName"];
Swift 3解决scheme
简单的工具类
class ArchiveUtil { private static let PeopleKey = "PeopleKey" private static func archivePeople(people : [Human]) -> NSData { return NSKeyedArchiver.archivedData(withRootObject: people as NSArray) as NSData } static func loadPeople() -> [Human]? { if let unarchivedObject = UserDefaults.standard.object(forKey: PeopleKey) as? Data { return NSKeyedUnarchiver.unarchiveObject(with: unarchivedObject as Data) as? [Human] } return nil } static func savePeople(people : [Human]?) { let archivedObject = archivePeople(people: people!) UserDefaults.standard.set(archivedObject, forKey: PeopleKey) UserDefaults.standard.synchronize() } }
模型类
class Human: NSObject, NSCoding { var name:String? var age:Int? required init(n:String, a:Int) { name = n age = a } required init(coder aDecoder: NSCoder) { name = aDecoder.decodeObject(forKey: "name") as? String age = aDecoder.decodeInteger(forKey: "age") } public func encode(with aCoder: NSCoder) { aCoder.encode(name, forKey: "name") aCoder.encode(age, forKey: "age") } }
如何打电话
var people = [Human]() people.append(Human(n: "Sazzad", a: 21)) people.append(Human(n: "Hissain", a: 22)) people.append(Human(n: "Khan", a: 23)) ArchiveUtil.savePeople(people: people) let others = ArchiveUtil.loadPeople() for human in others! { print("name = \(human.name!), age = \(human.age!)") }
首先,rmaddy的答案(上面)是正确的:实施NSCoding
没有帮助。 但是,你需要实现NSCoding
使用NSKeyedArchiver
和所有这一切,所以它只是多一步…通过NSData
转换。
示例方法
- (NSUserDefaults *) defaults { return [NSUserDefaults standardUserDefaults]; } - (void) persistObj:(id)value forKey:(NSString *)key { [self.defaults setObject:value forKey:key]; [self.defaults synchronize]; } - (void) persistObjAsData:(id)encodableObject forKey:(NSString *)key { NSData *data = [NSKeyedArchiver archivedDataWithRootObject:encodableObject]; [self persistObj:data forKey:key]; } - (id) objectFromDataWithKey:(NSString*)key { NSData *data = [self.defaults objectForKey:key]; return [NSKeyedUnarchiver unarchiveObjectWithData:data]; }
所以你可以包装你的NSCoding
对象在NSArray
或NSDictionary
或其他…
我有这个问题,试图将一个字典保存到NSUserDefaults
。 事实certificate,它不会保存,因为它包含NSNull
值。 所以我只是将字典复制到一个可变的字典中去除了空值然后保存到NSUserDefaults
NSMutableDictionary* dictionary = [NSMutableDictionary dictionaryWithDictionary:dictionary_trying_to_save]; [dictionary removeObjectForKey:@"NullKey"]; [[NSUserDefaults standardUserDefaults] setObject:dictionary forKey:@"key"];
在这种情况下,我知道哪些键可能是NSNull
值。
https://developer.apple.com/reference/foundation/userdefaults
一个默认对象必须是一个属性列表 – 也就是,一个实例(或集合,实例的组合):NSData,NSString,NSNumber,NSDate,NSArray或NSDictionary。
如果要存储任何其他types的对象,则通常应将其存档以创buildNSData的实例。 有关更多详情,请参阅首选项和设置编程指南。