0

我发现很难写入/读取自定义对象数组。在我的应用程序中,Contact 类有一个 NSDictionary 作为属性,而这个字典有一个数组作为键的对象。我用NSCoderNSKeyedArchiever序列化/反序列化我的对象,甚至尝试了 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 ...这是堆栈跟踪,但我没有其他错误(

4

2 回答 2

3

您不需要使用NSPropertyListSerializationself.phoneNumbers。NSDictionary 遵守NSCoding协议。

所以,[aCoder encodeObject:self.phoneNumbers forKey:@"phones"];应该够用了。

只要一个类遵守 NSCoding (几乎所有 Apple 提供的类都这样做),您就可以使用-encodeObject:forKey:,因为该方法将调用该对象的实现-encodeWithCoder:

于 2012-09-04T12:57:55.507 回答
3

我的专有库中有一个特殊的类,它会自动读取其属性列表并使用 getter 和 setter 对对象进行编码和解码。对不起,我不能在这里分享代码,但我至少可以一步一步地告诉你我的课程是如何工作的:

  1. 首先,类必须是实现NSCodingNSCopying协议。

  2. 在内部,使用和+ (void)initialize遍历类属性的定义。有关这些函数的详细信息,请参阅Objective-C 运行时编程指南class_copyPropertyList()property_getName()property_copyAttributeList()

  3. 对于每个属性,通过其属性列表运行并获取属性strncmp(attribute.name, "T", 1) == 0(是的,它是一个 c 字符串)。使用该属性值来确定属性的类型。例如,“i”表示int,“I”表示unsigned int,如果它以“{”开头,那么它就是一个struct等等。请参阅此页面上的类型编码

  4. 将属性名称-类型对存储在NSDictionary. 在属性迭代结束时,NSMutableDictionary使用类名作为键将此字典存储在静态和全局中。

  5. 为了支持自动编码,实现- (void)encodeWithCoder:(NSCoder *)aCoder遍历属性名称-类型对,调用属性getter方法(通常)并使用适当的方法(例如,,,等)- (returnType)propertyName在编码器内部对其进行编码。encodeType:encodeInt:encodeFloat:encodeObject:encodeCGPoint:

  6. 为了支持自动解码,实现通过属性名称-类型对进行迭代,使用适当的方法(例如, ,等)- (id)initWithCoder:(NSCoder *)aDecoder从解码器中对其进行解码。并调用属性设置器方法(通常)。decodeTypeForKey:decodeIntForKey:decodeFloatForKey:decodeObjectForKey:decodeCGPointForKey:- (void)setPropertyName:

  7. 实现一个触发编码的实例方法(幸运的是我可以在这里分享这个方法^__^):

    NSMutableData *data = [NSMutableData data];
    NSKeyedArchiver *arc = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
    [arc encodeRootObject:self];
    [arc finishEncoding];
    [arc release];
    return data;
    
  8. 一旦你有了它,NSData你就可以用它做任何事情,比如 callwriteToFile:atomically:甚至[[NSUserDefaults standardUserDefaults] setObject:[self wrapInNSData] forKey:key].

  9. 此外,实现一个类方法,该方法返回从文件加载的对象的新实例:

    NSKeyedUnarchiver *unarc = [[NSKeyedUnarchiver alloc] initForReadingWithData:[NSData dataWithContentsOfFile:dataFilePath]];
    MyCoolFileDataStore *data = [unarc decodeObject];
    [unarc release];
    return data;
    
  10. 最后,为了使另一个对象类支持这种自动编码-解码,该类需要扩展特殊类。

抱歉,有点啰嗦,但就我而言,创建这个类所花费的额外麻烦确实节省了很多时间。今天奋斗,明天轻松;)

于 2012-09-04T13:08:05.607 回答