我是否更喜欢使用文字语法或构造函数来创建字典和数组?

时间:2012-09-21 18:07:12

标签: objective-c objective-c-literals

我正在阅读iOS开发人员指南以熟悉Objective-C语言,目前我对Container Literals和Subscript Notation这个主题有点混淆,因为它与创建像NSDictionary这样的对象有关。

我了解有多种方法可以创建NSDictionary个对象,包括键值编码(dictionaryWithObjects:forKeys:dictionaryWithObjectsAndKeys:,或者相应的初始值设定项)。 Source Link.

根据我的理解,有两种主要方法可以做到这一点,然后有另一种方式,这是通过使用容器文字,在这里演示:

NSDictionary *myDictionary = @{
   @"name" : NSUserName(),
   @"date" : [NSDate date],
   @"processInfo" : [NSProcessInfo processInfo]
};

哪种方式最好?使用Container Literal技术比前两个技术有什么好处,还是对程序员来说只是一件方便的事情?

我的印象是,它也是另一种更简单的方法来编码像数组这样的东西。这是真的还是我在这里缺少什么?这些技巧只是个人偏好的问题吗?

3 个答案:

答案 0 :(得分:11)

我不同意到目前为止发布的其他答案:几乎所有时间,使用新的容器文字语法比使用构造函数更好。它们有助于代码的正确性,而且兼容性并不是很重要。

代码正确性

容器文字确实是语法糖,但具体来说它们映射到“安全”构造函数方法+[NSArray arrayWithObjects:count:]+NSDictionary dictionaryWithObjects:forKeys:count:。直接使用这些方法之一构造数组或字典并不是那么方便,因此许多程序员发现使用arrayWithObjects:dictionaryWithObjectsAndKeys:更简单。然而,后一种方法有一个令人讨厌的缺陷:由于参数列表必须以nil终止,如果你传递nil你打算传递一个对象,你可以发现自己有意想不到的数组/字典内容。

例如,假设您正在设置一个字典映射您的某个模型对象的属性(也许您将把它作为JSON发送?):

NSDictionary *dictionary = [NSDictionary dictionaryWithObjectsAndKeys:
    person.name, @"name", person.title, @"title", person.address, @"address", 
    nil];

如果此代码遇到Person但未设置title的{​​{1}},则生成的字典将缺少@"address"键及其值。您可能花费数小时追踪为什么数据库中的某些人缺少地址(甚至可以看到上面的代码并撕掉你的头发,想知道为什么它在 c'mon时无法正常工作,我在那里设置它!)。我们很多人都有。

相比之下,如果你使用这样的文字形式:

NSDictionary *dictionary = @{
    @"name": person.name, @"title": person.title, @"address": person.address };

它将扩展为类似的东西:

id objects[] = { person.name, person.title, person.address };
id keys[] = { @"name", @"title", @"address" };
NSUInteger count = sizeof(objects) / sizeof(keys);
NSDictionary *dictionary = [NSDictionary dictionaryWithObjects:objects
                                                       forKeys:keys
                                                         count:count];                          

如果person.nameperson.title返回nil,此方法将抛出异常,而不是静默创建您不想要的数据。 (无论哪种方式,你都必须决定你希望代码如何处理nil标题,但这样你就能更快地解决问题。)当然,你可以自己编写这种“更安全”的形式,而不是使用相当的句法糖,但你确定你不会再回到写dictionaryWithObjectsAndKeys:的习惯,因为它更短吗?

兼容性

容器文字生成的代码(和number literals and boxed expressions就此而言)不使用新API,因此您可以使用Xcode 4.4或更新版本(或直接使用Clang 3.1或更新版本)编译它并部署到任何版本的基础。但是,如果源代码也将用于较旧的编译器或GNUStep,则需要考虑兼容性。 (虽然听起来GNUStep现在也很适合Clang。)

这不是问题的一部分,但由于它是在一个相关的主题上:对于新的对象下标语法来说,“同样”是正确的。这确实使用了仅在Mac OS X 10.6和iOS 6.0上定义的新方法......但这些方法由libarclite提供。 (您知道,当您尝试将ARC代码部署回iOS 4.3或Mac OS X 10.6时,链接到的库 - 它不仅仅适用于ARC了!)所以您需要做的就是在标题中声明它们,链接ARCLite,如果你还没有,你很高兴。

答案 1 :(得分:2)

没有“最佳方式”。使用对特定用例最好的。例如,如果您希望您的应用程序是可移植的(即只需要Foundation而不是UIKit的逻辑也可以在其他平台上运行,例如Mac OS X或带有GNUstep的Linux等),那么请避免使用文字语法 - 它们'不太便携。如果你只需要在iOS上工作,那就使用它们,因为它们很方便。

另外,这些符号只是语法糖 - 也就是说,它们映射到方法名称(据我所知,正是你在问题中提到的两种方法),所以他们不会t对性能,算法行为等有影响

是的,你猜对了:同样适用于新的下标语法 - 对于NSArray,它会调用- objectAtSubscriptedIndex:

答案 2 :(得分:1)

你可以在带有GNUstep和clang的GNU / Linux上使用它们。在我的大多数情况下,GNUstep使用clang比使用gcc的所有版本都要好得多。 (对不起,我应该编辑另一个答案,我是新手)