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

发布于 2024-12-24 16:14:45 字数 1396 浏览 2 评论 0原文

在网络调用返回的 NSData 上使用 NSJSONSerialization,我得到了 NSDictionaries 和 NSArray 的嵌套结构。

现在我想解析该树结构并为进一步使用做好准备。树的每个节点总是带有子节点的 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。

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

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

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

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

你们还有其他方法解决这个问题吗?我是否必须保存树结构的外部表示,指向每个键或IS实际上有一种存储对父节点的某种引用的方法?

非常非常感谢!

Using NSJSONSerialization on a returned NSData from a network call I get back a nested structure of NSDictionaries and 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). Every one of these nodes should have a back reference to it's parent node, containing the NSArray the sub node is part of.

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.

I learned, that I cannot just add a new key "parent" and set its value to the parent node dictionary. 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!!!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

Saygoodbye 2024-12-31 16:14:45

NSLog 行上的段错误是由于无限循环造成的。您可以通过子类化 NSMutableDictionary 并覆盖 -description 来明确排除打印键“parent”的值来打破这一点。但更一般地说,NSMutableDictionary 并不是设计来包含它自己的容器的。一方面,NSDictionary 保留其子对象,因此容器保留 foo,而 foo 保留容器,这会创建一个保留循环。

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

The segfault on the NSLog line is due to an infinite loop. You could break that by subclassing NSMutableDictionary and overriding -description to specifically exclude printing the value for the key "parent". More generally though, NSMutableDictionary isn't designed to include its own container. For one thing, NSDictionary retains its child objects, so container retains foo and foo retains container, which creates a retain cycle.

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.

那支青花 2024-12-31 16:14:45

在我看来,你可以在这里使用一个简单的目标 C 类和接口,就像

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

我不确定这是否是最好的方法一样,但你不应该使用 NSDictionary。出现分段错误的原因可能是因为反向引用在 NSLog 中创建了无限循环。

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

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

It seems to me that you can use a simple objective C class here with the interface like

@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. The reason why you are getting the segmentation fault is probably because of the back reference creating an infinite loop in the NSLog.

EDIT: Upon googling, I found that there is a class NSTreeNode which should make things simpler for you.

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

飘过的浮云 2024-12-31 16:14:45

我通过将嵌套字典包装在 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

如果我正确理解 NSProxy,这会拦截保留消息,从而防止嵌套时发生的保留循环直接添加包含反向引用的字典。无论如何,我知道我的代理正在被解除分配。

我发现这存在三个小问题。第一个是 NSDictionary:descriptionWithLocale:indent: 遍历其整个结构,这会导致已经指出的无限循环。好消息是,在 NSProxy 中“重写”它可以绕过每当您尝试重写属于类簇一部分的类(如 NSDictionary )时通常会遇到的粘性情况。

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

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

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:

@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. 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. 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).

The second problem is that calling MyObjectProxy:class returns the MyObjectProxy Class rather than the NSDictionary Class. 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. 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文