我以为我知道是什么导致了这个错误,但我似乎不知道我做错了什么。

以下是我得到的完整错误信息:

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类,我似乎不能弄清楚什么,虽然我做错了。

谢谢你的帮助!


当前回答

https://developer.apple.com/reference/foundation/userdefaults 默认对象必须是一个属性列表——也就是说,一个实例(对于集合来说,是实例的组合):NSData、NSString、NSNumber、NSDate、NSArray或NSDictionary。 如果你想存储任何其他类型的对象,你通常应该存档它来创建一个NSData的实例。有关详细信息,请参阅首选项和设置编程指南。

其他回答

https://developer.apple.com/reference/foundation/userdefaults 默认对象必须是一个属性列表——也就是说,一个实例(对于集合来说,是实例的组合):NSData、NSString、NSNumber、NSDate、NSArray或NSDictionary。 如果你想存储任何其他类型的对象,你通常应该存档它来创建一个NSData的实例。有关详细信息,请参阅首选项和设置编程指南。

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

Swift- 4 Xcode 9.1

试试这段代码

你不能存储映射器在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)

首先,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。结果是它不能保存,因为它包含NSNull值。所以我只是复制字典到一个可变字典删除空值,然后保存到NSUserDefaults

NSMutableDictionary* dictionary = [NSMutableDictionary dictionaryWithDictionary:dictionary_trying_to_save];
[dictionary removeObjectForKey:@"NullKey"];
[[NSUserDefaults standardUserDefaults] setObject:dictionary forKey:@"key"];

在这种情况下,我知道哪些键可能是NSNull值。