3

我正在阅读 iOS 开发人员指南以熟悉 Objective-C 语言,目前我对 Container Literals 和 Subscript Notation 的主题有些困惑,因为它与创建NSDictionary.

我知道有几种方法可以创建NSDictionary对象,包括键值编码(dictionaryWithObjects:forKeys:dictionaryWithObjectsAndKeys:,或它们相应的初始化程序)。源链接。

据我了解,有两种主要方法可以做到这一点,然后还有另一种方法是使用容器文字,如下所示:

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

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

我的印象是它也是编码数组之类的另一种更简单的方法。这是真的还是我在这里遗漏了什么?这些技术只是个人喜好问题吗?

4

3 回答 3

12

我不同意迄今为止发布的其他答案:几乎所有时候,使用新的容器文字语法比使用构造函数更好。它们有助于代码的正确性,而且对于兼容性并没有太多担心。

代码正确性

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

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

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

如果此代码遇到已设置Personno的对象title,则生成的字典将缺少@"address"键及其值。您可能会花费数小时来追踪为什么您的数据库中的一部分人丢失了地址(甚至看到上面的代码并撕下您的头发想知道为什么它不工作时来吧,我就在那里设置它!)。我们很多人都有。

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

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:因为写作更短而重新养成写作的习惯吗?

兼容性

由容器文字(以及数字文字和盒装表达式)生成的代码不使用新的 API,因此您可以使用 Xcode 4.4 或更高版本(或 Clang 3.1 或更高版本直接)编译它并部署到任何版本的 Foundation。但是,如果您的源代码也将与较旧的编译器或 GNUStep 一起使用,则您确实需要考虑兼容性。(虽然听起来 GNUStep 现在也适用于 Clang。)

这不是问题的一部分,但因为它是在一个相关的主题上:对于新的对象下标语法来说,“有点”也是如此。这确实使用了仅在 Mac OS X 10.6 和 iOS 6.0 上定义的新方法……但这些方法由libarclite. (你知道,当你尝试将 ARC 代码部署回 iOS 4.3 或 Mac OS X 10.6 时,链接的库——它不再只是用于 ARC!)所以你需要做的就是在标题中声明它们,链接如果您还没有 ARCLite,那么您就可以开始了。

于 2012-09-23T21:09:12.593 回答
2

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

此外,这些符号只是语法糖——也就是说,它们映射到方法名称(据我所知,正是你在问题中提到的两种方法),所以它们对性能没有任何影响,算法等

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

于 2012-09-21T18:26:50.297 回答
1

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

于 2012-09-22T16:50:01.787 回答