我以为我知道是什么原因导致了这个错误,但我似乎无法弄清我做错了什么。
以下是我得到的全部错误信息:
<pre>; 试图设置一个非属性列表对象( "<BC_Person: 0x8f3c140>"; )作为键personDataArray的NSUserDefaults值。 </pre>;
我有一个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;
}
在应用程序中的某个时刻,"BC_PersonClass "中的 "NSString "被设置,我有一个 "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
。你不能这样做。实现 "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"];
}
在我看来,自己跑遍数组并将对象编码为NSData是相当浪费的。你的错误BC_Person is a non-perty-list object
是在告诉你,框架不知道如何序列化你的person对象。
所以只需要确保你的人名对象符合NSCoding,然后你就可以简单地将你的自定义对象数组转换为NSData并存储到defaults。这里有一个操场:
编辑:写入`NSUserDefaults'在Xcode 7上被破坏了,所以playground将归档到数据和返回并打印输出。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中存储了一个自定义对象的数组。
首先,rmaddy's answer (over) is right: 实现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'之类的东西...。