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

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

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的实例。有关详细信息,请参阅首选项和设置编程指南。

其他回答

Swift 5: Codable协议可以用来代替NSKeyedArchiever。

struct User: Codable {
    let id: String
    let mail: String
    let fullName: String
}

Pref结构体是UserDefaults标准对象的自定义包装。

struct Pref {
    static let keyUser = "Pref.User"
    static var user: User? {
        get {
            if let data = UserDefaults.standard.object(forKey: keyUser) as? Data {
                do {
                    return try JSONDecoder().decode(User.self, from: data)
                } catch {
                    print("Error while decoding user data")
                }
            }
            return nil
        }
        set {
            if let newValue = newValue {
                do {
                    let data = try JSONEncoder().encode(newValue)
                    UserDefaults.standard.set(data, forKey: keyUser)
                } catch {
                    print("Error while encoding user data")
                }
            } else {
                UserDefaults.standard.removeObject(forKey: keyUser)
            }
        }
    }
}

所以你可以这样用:

Pref.user?.name = "John"

if let user = Pref.user {...

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

保存:

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

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

非常简单的方法

//MARK:- First you need to encoded your arr or what ever object you want to save in UserDefaults
//in my case i want to save Picture (NMutableArray) in the User Defaults in
//in this array some objects are UIImage & Strings

//first i have to encoded the NMutableArray 
let encodedData = NSKeyedArchiver.archivedData(withRootObject: yourArrayName)
//MARK:- Array save in UserDefaults
defaults.set(encodedData, forKey: "YourKeyName")

//MARK:- When you want to retreive data from UserDefaults
let decoded  = defaults.object(forKey: "YourKeyName") as! Data
yourArrayName = NSKeyedUnarchiver.unarchiveObject(with: decoded) as! NSMutableArray

//MARK: Enjoy this arrry "yourArrayName"