我需要为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项目,每次应用程序启动时我都需要在后台加载它。
实现这一目标的最佳方式是什么?
谢谢!
答案 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结构并访问方法以使用索引而不是parent
和children
字段的指针。索引将指向一个大的C数组trieNode结构,其中所有节点都是从。
此C数组可以保存在包装NDTrie
对象中的NSData对象中。然后,序列化和反序列化只是意味着保存/加载NSData对象(不包括endianess问题)。
答案 3 :(得分:0)
我认为你应该实施NSCoding协议:在你的initWithCoder:
创建一个包含所有children
的NSArray,并在encodeWithCoder:
中重新分配一个这样的结构数组。
通过这种方式,您将能够在项目的其余部分中使用原始的struct数组。