简体   繁体   English

嵌套的NSDictionary结构-如何保留对树中每个节点的父级的引用

[英]Nested NSDictionary Structure - How to hold a reference to the parent of every node in the tree

Using NSJSONSerialization on a returned NSData from a network call I get back a nested structure of NSDictionaries and NSArrays. 在通过网络调用返回的NSData上使用NSJSONSerialization,我得到了NSDictionaries和NSArrays的嵌套结构。

Now I wanted to parse that tree structure and prepare it for further use. 现在,我想解析该树结构,并准备将其进一步使用。 Each node of the tree always carries an NSArray of sub nodes (NSDictionaries). 树的每个节点始终带有一个NSArray的子​​节点(NSDictionaries)。 Every one of these nodes should have a back reference to it's parent node, containing the NSArray the sub node is part of. 这些节点中的每个节点都应对其父节点进行反向引用,其中包含子节点所属的NSArray。

This is a basic example of the structure I am talking about: 这是我正在谈论的结构的基本示例:

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

Each node is an NSDictionary and each sub nodes collection an NSArray, containing NSDictionaries. 每个节点是一个NSDictionary,每个子节点收集一个包含NSDictionaries的NSArray。

I learned, that I cannot just add a new key "parent" and set its value to the parent node dictionary. 我了解到,我不能只添加一个新的键“ parent”并将其值设置为父节点字典。 That creates a segfault when calling the object. 调用对象时会创建一个段错误。

Basic example of the code, creating the parent key: 创建父键的基本代码示例:

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

Why am I getting a segmentation fault? 为什么会出现细分错误? Is this an infinite loop while printing out the description of the structure because of the back reference in the parent key of the node? 由于节点的父键中的反向引用,在打印结构的描述时这是一个无限循环吗?

Dou you guys have any other approach to this problem here? 你们在这里还有其他方法可以解决这个问题吗? Do I have to hold an external representaion of the tree structure, pointing to each key or IS there actually a way of storing some kind of reference to the parent node?? 我一定要抱树结构的外部表达中,指向每个键或者有实际存储某种参考父节点的一种方式?

Many, many thanks in advance!!! 提前非常感谢!!!

The segfault on the NSLog line is due to an infinite loop. NSLog行上的段错误归因于无限循环。 You could break that by subclassing NSMutableDictionary and overriding -description to specifically exclude printing the value for the key "parent". 您可以通过子类化NSMutableDictionary并覆盖-description来打破这一点,以专门排除打印键“ parent”的值。 More generally though, NSMutableDictionary isn't designed to include its own container. 不过,更笼统地说,NSMutableDictionary并非旨在包括其自己的容器。 For one thing, NSDictionary retains its child objects, so container retains foo and foo retains container, which creates a retain cycle. 一方面,NSDictionary保留其子对象,因此container保留foo,而foo保留容器,这创建了一个保留周期。

My approach would be to write your own model classes. 我的方法是编写自己的模型类。 You can use an NSMutableDictionary object to store child nodes, with a weak @property/ivar holding a reference to the parent node. 您可以使用NSMutableDictionary对象存储子节点,并使用弱@ property / ivar保存对父节点的引用。

It seems to me that you can use a simple objective C class here with the interface like 在我看来,您可以在此处使用带有以下接口的简单目标C类

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

I am not sure if this is the best way to do it, but you should not be using NSDictionary . 我不确定这是否是最好的方法,但是您不应该使用NSDictionary The reason why you are getting the segmentation fault is probably because of the back reference creating an infinite loop in the NSLog . 出现分段错误的原因可能是由于反向引用在NSLog创建了无限循环。

EDIT: Upon googling, I found that there is a class NSTreeNode which should make things simpler for you. 编辑:谷歌搜索后,我发现有一个类NSTreeNode,它应该使您更简单。

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

I got around the limitation that prevents nested NSDictionaries from referring back to containing NSDictionaries (cyclic graphs) by wrapping the nested dictionaries inside instances of NSProxy: 我通过将嵌套字典包装在NSProxy实例中来避免了嵌套NSDictionaries无法引用回包含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

If I understand NSProxy correctly, this intercepts retain messages which in turn prevents the retain cycles that occur when nested dictionaries containing back references are added directly. 如果我正确理解NSProxy,则此方法会截取保留消息,从而阻止了在直接添加包含反向引用的嵌套字典时发生的保留周期。 At any rate, I know my proxies are being dealloced. 无论如何,我知道我的代理人正在被调配。

There are three minor problems with this that I've found. 我发现了三个小问题。 The first is that NSDictionary:descriptionWithLocale:indent: walks its entire structure, which causes the infinite loop already pointed out. 首先是NSDictionary:descriptionWithLocale:indent:遍历其整个结构,这导致已经指出的无限循环。 The good news is that "overriding" it in NSProxy bypasses the sticky situation normally encountered whenever you try to override a class that's part of a class cluster (as NSDictionary is). 好消息是,当您尝试覆盖属于类集群的类时(如NSDictionary一样),在NSProxy中“覆盖”它会绕过通常遇到的棘手情况。

The second problem is that calling MyObjectProxy:class returns the MyObjectProxy Class rather than the NSDictionary Class. 第二个问题是,调用MyObjectProxy:class返回MyObjectProxy类,而不是NSDictionary类。 It's not a problem in my case but it's something to be aware of. 就我而言,这不是问题,但需要注意。

The third problem is that removing a child dictionary from a parent dictionary and deallocing the parent causes the corresponding MyObjectProxy:proxied to become a zombie, since MyObjectProxy can't retain the reference without reintroducing the retain cycle. 第三个问题是,从父字典中删除子字典并重新分配父字典会导致相应的MyObjectProxy:proxied成为僵尸,因为MyObjectProxy在不重新引入保留周期的情况下无法保留引用。 Again, it's not a problem in my case since I never remove individual nodes from my structure but ensuring that you treat the entire structure as immutable is a limitation to be aware of. 同样,这对我来说不是问题,因为我从不从结构中删除单个节点,但是要确保将整个结构视为不可变是要注意的一个限制。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM