Попытка установить объект non-property-list в качестве NSUserDefaults
Я думал, что знаю, что вызывает эту ошибку, но я не могу понять, что я сделал неправильно.
вот полное сообщение об ошибке я получаю:
Attempt to set a non-property-list object (
"<BC_Person: 0x8f3c140>"
) as an NSUserDefaults value for key personDataArray
у меня есть Person класс, который я думаю, соответствует NSCoding протокол, где у меня есть оба этих метода в моем классе person:
- (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;
}
в какой-то момент в приложении NSString на BC_PersonClass установлен, и у меня есть 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, я просто не могу понять, что, хотя я делаю неправильно.
Спасибо за помощь!
8 ответов:
опубликованный код пытается сохранить массив пользовательских объектов в
NSUserDefaults. Ты не можешь этого сделать. РеализацияNSCodingметоды не помогают. Вы можете хранить вещи, какNSArray,NSDictionary,NSString,NSData,NSNumberиNSDateнаNSUserDefaults.вам нужно преобразовать объект в
NSData(как у вас в каком-то коде) и сохраните этоNSDataнаNSUserDefaults. Вы даже можете хранитьNSArrayнаNSDataесли вам нужно.когда вы читаете назад массив вам нужно разархивировать
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.поэтому все, что нужно, это убедиться, что ваш объект person соответствует NSCoding, тогда вы можете просто преобразовать свой массив пользовательских объектов в NSData и сохранить его по умолчанию. Вот детская площадка:
Edit: пишу
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 Решение
простой класс полезности
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или что-то еще...
Swift-4 Xcode 9.1
попробуйте этот код
вы не можете хранить mapper в NSUserDefault, вы можете хранить только NSData, NSString, NSNumber, NSDate, NSArray или NSDictionary.
let myData = NSKeyedArchiver.archivedData(withRootObject: myJson) UserDefaults.standard.set(myData, forKey: "userJson") let recovedUserJsonData = UserDefaults.standard.object(forKey: "userJson") let recovedUserJson = NSKeyedUnarchiver.unarchiveObject(with: recovedUserJsonData)
у меня была эта проблема, пытаясь сохранить словарь в
NSUserDefaults. Оказывается, это не спасет, потому что он содержалNSNullзначения. Поэтому я просто скопировал словарь в изменяемый словарь, удалил нули, а затем сохранил вNSUserDefaultsNSMutableDictionary* 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.
Если вы хотите сохранить любой другой тип объекта, вы должны обычно архивировать его для создания экземпляра NSData. Дополнительные сведения см. В разделе Программирование параметров и настроек Руководство.
Comments