使用指向NSData的指针序列化struct

时间:2010-05-18 01:37:05

标签: iphone c objective-c cocoa serialization

我需要为Objective-C Trie实现(github上的NDTrie)添加某种归档功能,但我对C及其数据结构的经验很少。

struct trieNode
{
    NSUInteger key;
    NSUInteger count,
    size;
    id object;
    __strong struct trieNode ** children;
    __strong struct trieNode * parent;
};

@interface NDTrie (Private)
- (struct trieNode*)root;
@end

我需要的是从该根创建一个具有树结构的NSData - 或者以其他方式序列化/反序列化整个树(符合NSCoding?),但我不知道如何使用NSData和包含指针的C结构。

反序列化生成的对象的性能至关重要,因为这是一个iPhone项目,每次应用程序启动时我都需要在后台加载它。

实现这一目标的最佳方式是什么?

谢谢!

4 个答案:

答案 0 :(得分:2)

将trie节点结构重新实现为Objective C类。 e.g。

@interface TrieNode
{
    NSUinteger key;
    NSUInteger count;
    //NSUInteger size; // not needed if you use an NSArray for the children.
    id object;
    NSArray* children;
    TrieNode* parent;
}
// methods
@end

然后,您可以使用标准的Objective-C机制来存档和取消归档这些对象。

如果在实施上述并分析您的代码后,您发现性能有问题,您可以开始优化。例如,通过使用C结构指针来访问ivars,例如

aTrieNode->parent;

或用NS阵列替换NSArray等。

答案 1 :(得分:1)

假设您需要坚持使用直接C,因为事情已经设置好了,您需要做的事情实际上非常简单。

只需编写一个C函数将您的树写入磁盘,并假设有关排序(例如,您首先将其写入深度,从左到右)。对于任何Objective-C对象,将它们编码为NSData,并在流中写出这些对象的大小和字节。

当您重读数据时,只需根据您的排序假设重建树,并设置指向子项的指针。根据需要取消归档任何嵌入的Objective-C对象。

你可以用NSCoder以某种方式做到这一点,但是在那之外进行树重建可能更容易,因为你可以通过你想要的任何参数递归树,这对于NSCoding来说并不是很容易。

我确实有一些(桌面OS X)代码可以做一些与此非常相似的代码,没有嵌入对象,但它非常繁琐,而且我无法发布它。

该代码中的一个优化是将数据读入内部缓冲区,以MB块为单位(而不是每次为每个结构一次少量字节),然后从该缓冲区读取数据,尽管我我不确定它是否曾经过基准测试,无论如何它可能会或可能不会对iPhone产生重大影响。看起来也有类似的写作优化,这更像是一场胜利,正如我所理解的那样(iPhone写的很贵,或者我听说过)。

答案 2 :(得分:0)

你应该首先尝试简单的方法:

// serializing:
[myTrie writeToFile:myPath atomically:NO];

// deserializing
NDTrie* myTrie = [NDTrie trieWithContentsOfFile:myPath];

如果真的不够快,你可以考虑手动序列化底层结构。

修改

您明确表示数据量需要优化实施。

我建议重写trieNode结构并访问方法以使用索引而不是parentchildren字段的指针。索引将指向一个大的C数组trieNode结构,其中所有节点都是从。

分配的

此C数组可以保存在包装NDTrie对象中的NSData对象中。然后,序列化和反序列化只是意味着保存/加载NSData对象(不包括endianess问题)。

答案 3 :(得分:0)

我认为你应该实施NSCoding协议:在你的initWithCoder:创建一个包含所有children的NSArray,并在encodeWithCoder:中重新分配一个这样的结构数组。

通过这种方式,您将能够在项目的其余部分中使用原始的struct数组。