我发现很难编写/读取自定义对象数组。在我的应用程序中,Contact类有一个NSDictionary作为属性,这个字典有数组作为键的对象。 我使用 NSCoder 和 NSKeyedArchiever 序列化/反序列化我的对象,甚至尝试了 NSPropertyList 序列化。一旦开始序列化NSDictionary,我总是在序列化时遇到错误。这是我的代码,我没有找到关于如何序列化具有复杂结构的自定义对象的一般答案?
//Contact.m
//phoneNumbers is a NSDictionary
#pragma mark Encoding/Decoding
-(void)encodeWithCoder:(NSCoder *)aCoder
{
NSLog(@"Encoding");
[aCoder encodeObject:self.firstName forKey:@"firstName"];
NSLog(@"First name encoded");
[aCoder encodeObject:self.lastName forKey:@"lastName"];
NSLog(@"Last name encoded");
[aCoder encodeInt:self.age forKey:@"age"];
NSLog(@"Age encoded");
NSString *errorStr;
NSData *dataRep = [NSPropertyListSerialization dataFromPropertyList:self.phoneNumbers
format:NSPropertyListXMLFormat_v1_0
errorDescription:&errorStr];
NSLog(@"Data class %@", [dataRep class]);
if(!dataRep)
{
NSLog(@"Error encoding %@", errorStr);
}
[aCoder encodeObject:dataRep forKey:@"phones"];
NSLog(@"Encoding finished");
}
- (id) initWithCoder: (NSCoder *)coder
{
if (self = [super init])
{
[self setFirstName:[coder decodeObjectForKey:@"firstName"]];
[self setLastName:[coder decodeObjectForKey:@"lastName"]];
[self setAge:[coder decodeIntForKey:@"age"]];
NSString *errorStr;
NSData *data=[coder decodeObjectForKey:@"phones"];
NSDictionary *propertyList = [NSPropertyListSerialization propertyListFromData:data mutabilityOption:NSPropertyListImmutable format:NULL errorDescription:&errorStr];
if(!propertyList)
{
NSLog(@"Error %@", errorStr);
}
[self setPhoneNumbers:propertyList];
}
return self;
}
//Serializing/Deserializing an array of Contact objects:
#pragma mark Import/Export
//Export Contacts to file
-(void)exportContactsToFile
{
BOOL done=[NSKeyedArchiver archiveRootObject:self.contacts toFile:[PathUtility getFilePath:@"phonebook"]];
NSLog(@"Export done: %i", done);
}
//Import Contacts from file
-(void)importContactsFromFile
{
self.contacts = [NSKeyedUnarchiver unarchiveObjectWithFile:[PathUtility getFilePath:@"phonebook"]];
}
是否有一种通用的好方法来序列化/反序列化objective-c中的对象?谢谢 我得到的错误是: 0objc_msgSend 1 CF_Retain ... 这是堆栈跟踪,但我没有其他错误(
答案 0 :(得分:3)
您不应该将NSPropertyListSerialization
用于self.phoneNumbers。 NSDictionary遵守NSCoding
协议。
所以,[aCoder encodeObject:self.phoneNumbers forKey:@"phones"];
就足够了。
只要一个类遵循NSCoding(几乎所有Apple提供的类都这样做),你就可以使用-encodeObject:forKey:
,因为该方法将调用该对象的-encodeWithCoder:
答案 1 :(得分:3)
我的专有库中有一个特殊的类,它自动读取其属性列表,并使用getter和setter对对象进行编码和解码。对不起,我不能在这里分享代码,但我至少可以一步一步地为您提供课程的工作方式:
首先,该类必须实现NSCoding
和NSCopying
协议。
在+ (void)initialize
内,使用class_copyPropertyList()
,property_getName()
和property_copyAttributeList()
迭代通过类属性的定义。有关这些功能的详细信息,请参阅Objective-C Runtime Programming Guide。
对于每个属性,运行其属性列表并获取带有strncmp(attribute.name, "T", 1) == 0
的属性(是的,它是一个c字符串)。使用该属性值来确定属性的类型。例如,“i”表示int
,“I”表示unsigned int
,如果它以“{”开头,那么它是struct
等。请参阅this page on the Type Encoding。
将属性名称类型对存储在NSDictionary
中。在属性迭代结束时,使用类名作为键将此字典存储在静态和全局NSMutableDictionary
中。
要支持自动编码,请实现- (void)encodeWithCoder:(NSCoder *)aCoder
以通过属性名称类型对进行迭代,调用属性getter方法(通常为- (returnType)propertyName
)并使用适当的{在编码器内对其进行编码{1}}方法(例如encodeType:
,encodeInt:
,encodeFloat:
,encodeObject:
等。
要支持自动解码,请实施encodeCGPoint:
以通过属性名称类型对进行迭代,使用适当的- (id)initWithCoder:(NSCoder *)aDecoder
方法(例如decodeTypeForKey:
方法)从解码器对其进行解码(decodeIntForKey:
,{ {1}},decodeFloatForKey:
,decodeObjectForKey:
等)。并调用属性setter方法(通常为decodeCGPointForKey:
)。
实现一个触发编码的实例方法(幸运的是我可以在这里分享这个方法^ __ ^):
- (void)setPropertyName:
获得NSMutableData *data = [NSMutableData data];
NSKeyedArchiver *arc = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
[arc encodeRootObject:self];
[arc finishEncoding];
[arc release];
return data;
后,您可以使用NSData
甚至writeToFile:atomically:
。
此外,实现一个类方法,该方法返回从文件加载的对象的新实例:
[[NSUserDefaults standardUserDefaults] setObject:[self wrapInNSData] forKey:key]
最后,为了使另一个对象类支持这种自动编码解码,该类需要扩展特殊类。
对不起,这有点长,但对于我的情况,我创建这个课程的额外麻烦确实节省了很多时间。今天奋斗,明天轻松;)