2011-12-30 70 views
0

对来自网络调用的返回NSData使用NSJSONSerialization我找回NSDictionaries和NSArrays的嵌套结构。嵌套的NSDictionary结构 - 如何持有对树中每个节点的父节点的引用

现在我想解析该树结构并为进一步使用做好准备。树的每个节点总是携带一个NSArray的子​​节点(NSDictionaries)。这些节点中的每一个都应该有一个对其父节点的反向引用,包含子节点所属的NSArray。

这是我说的是该结构的一个基本的例子:

Node { 
nodes:[ 
    node {parent:Node,name:foo}, 
    node {parent:Node,name:bar}, 
    node {parent:Node,name:baz}, 
] 
,name:root} 

每个节点是一个NSDictionary并且每个子节点集合一个NSArray,含有NSDictionaries。

我了解到,我不能只是添加一个新的关键“父母”,并将其值设置为父节点字典。这在调用对象时会创建段错误。

代码的基本例如,在创建父键:

NSMutableDictionary * foo = [NSMutableDictionary dictionaryWithObjectsAndKeys:@"foo",@"name",[NSNumber numberWithInt:1],@"value",nil]; 
NSMutableDictionary * bar = [NSMutableDictionary dictionaryWithObjectsAndKeys:@"bar",@"name",[NSNumber numberWithInt:2],@"value",nil]; 
NSMutableDictionary * baz = [NSMutableDictionary dictionaryWithObjectsAndKeys:@"baz",@"name",[NSNumber numberWithInt:3],@"value",nil]; 

NSMutableArray *array = [NSMutableArray arrayWithObjects:foo,bar,baz,nil]; 

NSMutableDictionary * container = [NSMutableDictionary dictionaryWithObjectsAndKeys:@"root",@"name",array,@"nodes",nil]; 

[foo setValue:container forKey:@"parent"]; 

NSLog(@"%@",foo); // <-- segfault here 

为什么会出现分段错误?由于节点的父键中的反向引用,打印出结构的描述时,这是一个无限循环吗?

你们有没有其他办法解决这个问题?我是否必须持有树结构的外部表示,指向每个键或实际存在某种方式来存储对父节点的某种引用?

很多,很多预先感谢!

回答

1

在我看来,你可以在这里使用一个简单的目标C级与界面像

@interface Node : NSObject { 
    Node    *parent; 
    NSMutableArray *nodes; 
    NSString   *name 
} 
@end 

我不知道这是否是做的最好的方法,但你不应该使用NSDictionary 。你得到分段错误的原因可能是因为back reference在NSLog中创建了一个无限循环。

编辑:在谷歌搜索,我发现有一个类NSTreeNode应该让你的事情变得更简单。

http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/NSTreeNode_class/Introduction/Introduction.html

+0

谢谢!我有点期待答复,现在我相信我需要写自己的模型。通过这个我可以拿回参考。 – Nonlinearsound 2011-12-30 17:03:18

+0

@Nonlinearsound不客气。请看看NSTreeNode类。我认为应该更好。 – MadhavanRP 2011-12-30 17:12:11

+0

再次感谢。我正在为iOS开发,不幸的是NSTreeNode不支持那里。但无论如何,我会仔细看看它,即使只是想了解它的结构。 – Nonlinearsound 2011-12-30 17:24:47

2

NSLog行上的segfault是由于无限循环造成的。你可以通过继承NSMutableDictionary和覆盖-description来明确排除打印键“parent”的值。但更一般的说,NSMutableDictionary并没有被设计成包含它自己的容器。首先,NSDictionary保留它的子对象,所以容器保留foo和foo保留容器,这就创建了一个保留循环。

我的方法是编写自己的模型类。您可以使用NSMutableDictionary对象来存储子节点,并使用一个弱@属性/ ivar来存储对父节点的引用。

+0

非常感谢Andrew的回答。随着你和MadhavanRP的提议,我会写下我自己的小模型。仅仅使用这个结构太方便了,NSJSONSerialization返回并且用额外的后向引用功能来扩展它。 – Nonlinearsound 2011-12-30 17:06:19

+0

这通常是尝试使用内置类而不是滚动自己的类的一种合理方法。但是,如果内置的类具有导致问题的限制,则不应该害怕编写自己的类。祝你好运! – 2011-12-30 17:11:09

0

我周围,防止嵌套NSDictionaries从返回参考包含通过缠绕内部NSProxy实例的嵌套词典NSDictionaries(循环图)的限制:

 
@interface MyObjectProxy : NSProxy { 
    id proxied; 
} 

-(id)initWithObject:(id)obj; 

@end 

@implementation MyObjectProxy 

-(id)initWithObject:(id)obj 
{ 
    proxied = obj; 
    return self; 
} 

-(void)forwardInvocation:(NSInvocation*)invocation 
{ 
    [invocation invokeWithTarget:proxied]; 
} 

-(NSMethodSignature*)methodSignatureForSelector:(SEL)selector 
{ 
    return [[proxied class] instanceMethodSignatureForSelector:selector]; 
} 

-(NSString*)descriptionWithLocale:(id)locale indent:(NSUInteger)level 
{ 
    return [[self class] description]; 
} 

@end 

如果我正确理解NSProxy ,这个拦截保留了消息,这反过来又防止了当直接添加包含后向引用的嵌套字典时发生的保留周期。无论如何,我知道我的代理人正在交易。

有这个,我已经发现了三个小问题。首先是NSDictionary:descriptionWithLocale:indent:行走其整个结构,这导致无限循环已经指出。好消息是,在NSProxy中“覆盖”它可以绕过通常遇到的困境,无论何时您试图覆盖作为类集群一部分的类(如NSDictionary所示)。

第二个问题是,调用MyObjectProxy:class返回MyObjectProxy类而非的NSDictionary类。这对我来说不是问题,但应该注意。

第三个问题是,从父字典中删除子字典并释放父项会导致相应的MyObjectProxy:proxied成为僵尸,因为MyObjectProxy无法在不重新引入保留周期的情况下保留该引用。再说一次,这对我来说不是问题,因为我从不从我的结构中删除单个节点,但确保将整个结构视为不可变是一种需要注意的限制。

+0

我想我应该注意使用嵌套的NSDictionaries/NSArrays的优点,除了不必编写自己的类。主要的优点是NSDictionary/NSArray是符合键值编码的,我认为这是一些开发人员忽略的。这意味着,例如,如果我有一个公司的NSDictionary表示,而该公司的NSDictionary表示又具有嵌套的NSArray地址,则可以使用[myCompanyDict valueforKeyPath:@“addresses.state”]获取所有状态并获取列表的国家作为NSArray。 – charshep 2013-01-07 18:13:45

相关问题