以编程方式创建字典属性列表

10
我想编写一段程序,动态创建一个字典用来提供给我的UITableView数据,但我遇到了些困难。我想创建一个类似这个属性列表(图片)的字典,可能有一些不同的条目。
我查看了"属性列表编程指南:以编程方式创建属性列表",并编写了自己的一个小示例:
//keys

NSArray *Childs = [NSArray arrayWithObjects:@"testerbet", nil];
NSArray *Children = [NSArray arrayWithObjects:@"Children", nil];
NSArray *Keys = [NSArray arrayWithObjects:@"Rows", nil];
NSArray *Title = [NSArray arrayWithObjects:@"Title", nil];

//strings

NSString *Titles = @"mmm training";

//dictionary 

NSDictionary *item1 = [NSDictionary dictionaryWithObject:Childs, Titles forKey:Children , Title];
NSDictionary *item2 = [NSDictionary dictionaryWithObject:Childs, Titles forKey:Children , Title];
NSDictionary *item3 = [NSDictionary dictionaryWithObject:Childs, Titles forKey:Children , Title];
NSArray *Rows = [NSArray arrayWithObjects: item1, item2, item3, nil];
NSDictionary *Root = [NSDictionary dictionaryWithObject:Rows forKey:Keys];

// NSDictionary *tempDict = [[NSDictionary alloc] //initWithContentsOfFile:DataPath];
NSDictionary *tempDict = [[NSDictionary alloc] initWithDictionary: Root];

我正在尝试在我的表视图中使用这个层次结构的数据。

因此,我想知道如何以编程方式创建我的属性列表(字典),以便我可以用自己的数组填充它。

我还是 iPhone 开发的新手,所以请多包涵。 ;)

4个回答

25
这种情况下,“授人以鱼不如授人以渔”的方法比“授人以鱼”更有帮助。一旦你理解了基本原则和NSDictionary API,就会更容易地创建自己的定制解决方案。以下是一些观察和学习要点:
  • 方法+dictionaryWithObject:forKey:用于创建只有一个键值对的NSDictionary。该方法调用后不会接受每个冒号(:)之后的逗号分隔参数,而是只能接受一个。若要创建具有多个键值对的字典,请使用两个相关方法中的一个:+dictionaryWithObjects:forKeys:,它接受包含值和键的两个NSArray对象,或者+dictionaryWithObjectsAndKeys:,它交替使用(对象、键、对象、键)并以 nil 参数终止。
  • 简化创建代码。你不需要上千个局部变量来创建这个东西。在适当的地方使用内联参数。一种方法是在代码中将字典作为NSMutableDictionary构建,然后(必要时)通过调用它的-copy方法将其复制为不可变副本。 (请记住,复制方法会返回一个新对象,你必须释放它以避免内存泄漏。)这样,你就不必为每个值都有一个变量,因此可以在每个级别进行“一次性”结构的创建。
  • 使用+arrayWithObject:来创建具有单个对象的NSArray。
  • (样式建议)不要使用大写字母开头命名变量、方法或函数。(注意:类名等带首字母大写的变量被SO突出显示。)这绝对会帮助其他阅读你代码的人不会被你的命名方案所混淆。

只是为了让你感受一下在代码中创建链接图中的字典可能会是什么样子……(我忽略了你选择的变量名称,并为完整性使用了不同的方法。)

NSDictionary *item1 = [NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:@"Screen J",[NSNumber numberWithInt:3],nil]
                                                  forKeys:[NSArray arrayWithObjects:@"Title",@"View",nil]];
NSDictionary *item2 = [NSDictionary dictionaryWithObjectsAndKeys:
                                        @"Screen I", @"Title", 
                                        [NSArray arrayWithObject:item1], @"Children", 
                                        nil];
...

2
我不确定我理解这里的基本目标。
似乎在运行时,您正在使用许多子节点构建深层字典。但是,您是用静态代码构建所有内容的...为什么不能简单地制作一个属性列表(就像您有图像的那个)并将其读入NSDictionary中呢?NSDictionary和NSArray都有方法,可以让您简单地读取文件并获取整个填充对象。然后更容易编辑和理解。该方法是`dictionaryWithContentsOfFile`。
如果所有数据确实在放入字典之前在运行时创建,那么看起来您需要非常不同的递归式代码而不是给出的平面示例。
最后,我个人不喜欢NSDictionary中使用`dictionaryWithObjects:forKeys:`方法来构建字典。如果您必须以这种方式处理事情,我非常喜欢替代方法`dictionaryWithObjectsAndKeys:`,它执行相同的操作,但将键与对象一起保留。
NSDictionary *item1 = [NSDictionary dictionaryWithObjectsAndKeys:
                       @"Screen J",
                       @"Title",
                       [NSNumber numberWithInt:3],
                       @"View"];

1
我想测试一下自己是否能够做到,这样我以后就可以尝试使它更加递归和动态,例如像这样: <code>for (int i = 0; i < 4; ++i) { NSMutableArray *theChildren = [NSMutableArray arrayWithCapacity: 1]; [theChildren addObject: [NSString stringWithFormat: @"tester %d", i]]; NSString *aTitle = [NSString </code> 你可以在下面看到“完整”的代码。 实际上,我的目标更具有动态性。我正在尝试至少让字典工作,这样我就可以开始使其动态化。 最后但并非最不重要的是,感谢您的反馈。 - jovany

0
NSMutableDictionary *topLevel = [NSMutableDictionary dictionary];

NSMutableDictionary *item1 = [NSMutableDictionary dictionary];
NSString *item1title = [NSString stringWithString:@"Title 1"];
NSMutableDictionary *item1children = [NSMutableDictionary dictionary];

//  create children
NSString *item1child1 = [NSString stringWithString:@"item 1, child 1"];

NSMutableDictionary *item1child2 = [NSMutableDictionary dictionary];
NSString *item1child2title = [NSString stringWithString:@"Title 1-2"];
NSMutableDictionary *item1child2children = [NSMutableDictionary dictionary];

NSString *item1child2child1 = [NSString stringWithString:@"item 1, child 2, child 1"];
NSString *item1child2child2 = [NSString stringWithString:@"item 1, child 2, child 2"];

[item1child2 setObject:item1child2title forKey:@"Title"];
[item1child2children setObject:item1child2child1 forKey:@"item 1 child2 child 1"];
[item1child2children setObject:item1child2child2 forKey:@"item 1 child2 child 2"];

[item1child2 setObject:item1child2children forKey:@"children"];

//  add children to dictionary
[item1children setObject:item1child1 forKey:@"item1 child1"];
[item1children setObject:item1child2 forKey:@"item1 child2"];

//  add to item 1 dict
[item1 setObject:item1title forKey:@"Title"];
[item1 setObject:item1children forKey:@"children"];

NSMutableDictionary *item2 = [NSMutableDictionary dictionary];
NSString *item2title        = [NSString stringWithString:@"Title"];
NSMutableDictionary *item2children  = [NSMutableDictionary dictionary]; 

NSString *item2child1 = [NSString stringWithString:@"item 2, child 1"];
NSString *item2child2 = [NSString stringWithString:@"item 2, child 2"];
NSString *item2child3 = [NSString stringWithString:@"item 2, child 3"];

//  add children to dictionary
[item2children setObject:item2child1 forKey:@"item2 child1"];
[item2children setObject:item2child2 forKey:@"item2 child2"];
[item2children setObject:item2child3 forKey:@"item2 child3"];

//  add to item 2 dict
[item2 setObject:item2title forKey:@"Title"];
[item2 setObject:item2children forKey:@"children"];

[topLevel setObject:item1 forKey:@"Item 1"];
[topLevel setObject:item2 forKey:@"Item 2"];

谢谢,我会去看看并尝试一下,看看我是否能正确使用这些字典。我还注意到你没有使用任何数组(例如在图片链接和示例应用程序中看到的子项),但愿它仍然有效;即使它不行,你也有我的感激之情。 再次感谢。 - jovany

0

首先,太棒了!谢谢你。我非常感激你的解释和代码片段。 既然你给了我这么好的解释,我希望你不介意我再问几个问题。

首先,我按照你的建议去做了,这是我的成果: (这次我使用了我的原始属性列表,而不是示例,所以这就是钻取表格获取它的树形结构的地方)。

http://img509.imageshack.us/img509/7523/picture2lsg.png

NSDictionary *root = [NSMutableDictionary dictionary];
NSDictionary *item1 = [NSDictionary dictionaryWithObject:[NSArray arrayWithObject:@"VirtuaGym Online"] forKey:[NSArray arrayWithObjects:@"Title"]];
NSDictionary *item2 = [NSDictionary dictionaryWithObject:[NSArray arrayWithObject:@"Do the training"] forKey:[NSArray arrayWithObjects:@"Title"]];
NSDictionary *item3 = ... 

[root setObject:item1 forKey:@"Item 1"];
[root setObject:item2 forKey:@"Item 2"];

我还进行了一些研究,并尝试了其他一些输入。

NSMutableArray *Rows = [NSMutableArray arrayWithCapacity: 1];

for (int i = 0; i < 4; ++i) {
  NSMutableArray *theChildren = [NSMutableArray arrayWithCapacity: 1];
  [theChildren addObject: [NSString stringWithFormat: @"tester %d", i]];
NSString *aTitle = [NSString stringWithFormat: @"Item %d", i];
  NSDictionary *anItem = [NSDictionary dictionaryWithObjectsAndKeys: aTitle, @"Title", theChildren, @"Children"];
  [Rows addObject: anItem];
}

NSDictionary *Root = [NSDictionary withObject: Rows andKey: @"Rows"];

我决定测试这两个,但它却做了我想要的事情。它给了我一个EXC_BAD_ACCESS错误。

我也在想,既然我看到你在代码片段中使用数字,那么你也可以使用NSString,因为这是plist使用的..当然可能完全不对

NSDictionary *item1 = [NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:@"Screen J",[NSNumber numberWithInt:3],nil]
                                                  forKeys:[NSArray arrayWithObjects:@"Title",@"View",nil]];

第三个问题是关于我的应用程序可能采用的方法。我有一个XML解析器,它将某些信息保存在不同的数组中。我想将这些信息用于我的下钻UITableviews(infoFirstScreen[] infoSecondScreen[] infoThirdScreen[])。提供的信息必须像我向您展示的树一样连接起来。这就是我想在代码中构建字典的原因,这样我就可以从我的数组中获取信息并将其插入到这里。我的问题是,您认为我的方法正确、错误还是有更快的方法?

再次感谢您的解释;)


如果你想提出一个单独的问题,最好发表一个新的问题,这样它就能获得更多的关注和回答。 - Quinn Taylor

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接