2011-12-30 69 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

相關問題