Попытка установить объект 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, я просто не могу понять, что, хотя я делаю неправильно.



Спасибо за помощь!

591   8  

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 значения. Поэтому я просто скопировал словарь в изменяемый словарь, удалил нули, а затем сохранил в 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.

Если вы хотите сохранить любой другой тип объекта, вы должны обычно архивировать его для создания экземпляра NSData. Дополнительные сведения см. В разделе Программирование параметров и настроек Руководство.

Comments

    Ничего не найдено.