我正在阅读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技术比前两个技术有什么好处,还是对程序员来说只是一件方便的事情?
我的印象是,它也是另一种更简单的方法来编码像数组这样的东西。这是真的还是我在这里缺少什么?这些技巧只是个人偏好的问题吗?
答案 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.name
或person.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的所有版本都要好得多。 (对不起,我应该编辑另一个答案,我是新手)