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

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

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

谢谢你的帮助!


当前回答

保存:

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"];

其他回答

您发布的代码尝试将一个自定义对象数组保存到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"];
}

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

我遇到了这个问题,最终发现这是因为我试图使用NSNumber作为字典键,属性列表只允许字符串作为键。setObject:forKey:的文档没有提到这个限制,但是它链接到的About属性列表页面提到了:

By convention, each Cocoa and Core Foundation object listed in Table 2-1 is called a property-list object. Conceptually, you can think of “property list” as being an abstract superclass of all these classes. If you receive a property list object from some method or function, you know that it must be an instance of one of these types, but a priori you may not know which type. If a property-list object is a container (that is, an array or dictionary), all objects contained within it must also be property-list objects. If an array or dictionary contains objects that are not property-list objects, then you cannot save and restore the hierarchy of data using the various property-list methods and functions. And although NSDictionary and CFDictionary objects allow their keys to be objects of any type, if the keys are not string objects, the collections are not property-list objects.

(强调我的)

我有这个问题,试图保存一个字典到NSUserDefaults。结果是它不能保存,因为它包含NSNull值。所以我只是复制字典到一个可变字典删除空值,然后保存到NSUserDefaults

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

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

Swift使用@propertyWrapper

将可编码对象保存为UserDefault

@propertyWrapper
    struct UserDefault<T: Codable> {
        let key: String
        let defaultValue: T

        init(_ key: String, defaultValue: T) {
            self.key = key
            self.defaultValue = defaultValue
        }

        var wrappedValue: T {
            get {

                if let data = UserDefaults.standard.object(forKey: key) as? Data,
                    let user = try? JSONDecoder().decode(T.self, from: data) {
                    return user

                }

                return  defaultValue
            }
            set {
                if let encoded = try? JSONEncoder().encode(newValue) {
                    UserDefaults.standard.set(encoded, forKey: key)
                }
            }
        }
    }




enum GlobalSettings {

    @UserDefault("user", defaultValue: User(name:"",pass:"")) static var user: User
}

用户模型确认可编码

struct User:Codable {
    let name:String
    let pass:String
}

如何使用

//Set value 
 GlobalSettings.user = User(name: "Ahmed", pass: "Ahmed")

//GetValue
print(GlobalSettings.user)