OC语言中的语法对iOS的“yak-shaving”(翻译)|青训营笔记

116 阅读7分钟

这是我参与「第四届青训营-iOS专场」笔记创作活动的第4天。

本篇文章将会翻译Joey deVilla的《Objective-C’s New NSNumber, NSArray and NSDictionary Syntaxes Mean Less “Yak Shaving” for iOS and OS X Developers》(原文地址为:www.globalnerdy.com/2012/09/23/…)。

“Yak shaving” (耗牛剃毛)是一个用来描述一个看似毫无意义的活动的术语,或者如杰里米-布朗所说,你实际上是为了完成一个更大的任务而不得不做它。

“你看,yak shaving是你在做的事情,当你在做一些愚蠢的、琐碎的小任务时,这些任务与你应该做的事情没有明显的关系,但却有一连串的12个因果关系将你正在做的事情与原来的元任务联系起来。”  

许多编程语言,特别是那些早于现代脚本语言的语言,经常要求程序员做一些“Yak shaving”的工作,Objective-C也不例外。有了XCode 4.5及其新的Clang编译器,你可以得到一些不错的语法糖,我相信这些语法糖会让你说 "终于来了!",并让你免去相当多的“Yak shaving”工作。

NSNumber Literals

如果你用Objective-C编码,哪怕只是一点点,你可能已经遇到了NSString,在为OS X的Foundation框架开发时使用的不可变的字符串类型。如果你有,你很可能见过这样的赋值:

NSString *myString = @"Hello, world!";

@是一个方便的缩写,它向编译器说明Hello, world!是一个NSString。如果没有这个语法糖,我们就必须这样写下面这行代码:

NSString *myString = [NSString stringWithCString:"Hello, world!"];

到目前为止,NSNumber还没有这样的语法糖,Foundation的类型是用来将数值包装在一个对象中的。这对于做一些事情是很方便的,比如包装数字,这样你就可以把它们存储在像NSArrayNSDictionary这样的集合类中,而这些集合类只能存储对象。

在当前版本的Objective-C(XCode 4.5附带的)之前,这是你如何给NSNumbers分配一些数值:

NSNumber *meaningOfLife = [NSNumber numberWithInt:42];
NSNumber *ussReliantPrefixCode = [NSNumber numberWithUnsignedInt:16309];
NSNumber *floatPi = [NSNumber numberWithFloat:3.14159];
NSNumber *doublePi = [NSNumber numberWithFloat:3.14159265358979];
NSNumber *avogadrosNumber = [NSNumber numberWithDouble:6.02214129E+23];

仅仅为了将一个简单的数字类型装箱到一个对象中,就需要做很多工作。幸运的是,Objective-C现在支持NSNumber字样。就像NSString字样一样,NSNumber字样前面有@符号。

下面的代码使用了NSNumber字头,与上面的代码相当,但需要更少的输入,而且更容易阅读。

NSNumber *meaningOfLife = @42;
NSNumber *ussReliantPrefixCode = @16309U;
NSNumber *floatPi = @3.14159F;
NSNumber *doublePi = @3.14159265358979;
NSNumber *avogadrosNumber = @6.02214129E+23;

Array Literals, NSArray , and NSMutableArray

初始化NSArray并以老方法访问其元素

如果你是从JavaScript、Python或Ruby这样的语言来到Objective-C的,你会习惯于使用字面符号进行数组赋值。

假设你想创建一个包含《权力的游戏》中斯塔克家族成员名字的数组。下面是你在Python和Ruby中的做法(在JavaScript中也是如此,尽管你可能想在starkFamily前加上var关键字)。

starkFamily = [
    "Eddard",
    "Catelin",
    "Robb",
    "Sansa",
    "Arya",
    "Bran",
    "Rickon"
]

下面是你如何使用Objective-C和NSArray创建上面的数组 -- 使用arrayWithObjects:方法,它期望一个以逗号分隔的对象列表,以nil结尾。

NSArray *starkFamily = [NSArray arrayWithObjects:
    @"Eddard",
    @"Catelin",
    @"Robb",
    @"Sansa",
    @"Arya",
    @"Bran",
    @"Rickon",
    nil
];

这并没有多打多少字,但你必须记住用nil来标记列表的结尾。

更麻烦的是数组访问。在 JavaScript、Python 和 Ruby 中,如果你想访问索引为 2 的 starkFamily 元素,你会这样做:

starkFamily[2]

在早期的Objective-C版本中,你可以通过以下方式访问该元素:

[starkFamily objectAtIndex:2]

哇,这可真够笨的。即使有XCode的自动完成功能(类似于Visual Studio的Intellisense),对于像数组元素访问这样简单的事情,仍然需要大量的输入。

 

初始化NSArray并以新方式访问其元素

在最新版本的Objective-C中,我们有了NSArray字面意义。下面是你如何使用NSArray字面来初始化starkFamily数组。  

NSArray *starkFamily = @[
    @"Eddard",
    @"Catelin",
    @"Robb",
    @"Sansa",
    @"Arya",
    @"Bran",
    @"Rickon"
];

NSArray字面符号看起来几乎与JavaScript、Python和Ruby的数组字面符号一样。最大的区别是,NSArray字头以@字符开始,就像NSStringNSNumber字头一样。

至于从NSArray中访问元素,你现在可以用一个更熟悉的符号来做。

starkFamily[2]

终于来了! 我更喜欢myArray[index]而不是[myArray objectAtIndex:index]

 

使用阵列字样初始化NSMutableArrays

NSArray是一个不可变的类型;一旦初始化,你就不能重新分配、添加或删除它的任何元素。NSMutableArrayNSArray的一个子类,是可变的。下面是你如何使用NSArray字面来初始化一个NSMutableArray

NSMutableArray *starkFamily = [@[
    @"Eddard",
    @"Catelin",
    @"Robb",
    @"Sansa",
    @"Arya",
    @"Bran",
    @"Rickon"
] mutableCopy];

在上面的代码中,我们使用一个数组字面创建了一个NSArray,并对其调用了NSArraymutableCopy: 方法。结果是一个包含数组字面值的NSMutableArray

NSArray一样,你现在可以使用标准的数组符号来访问NSMutableArray的元素...

starkFamily[2]

  ...当然,由于数组是可变的,你可以做这样的事情:

starkFamily[2] = @"Tony";
[starkFamily removeObjectAtIndex:0]

Dictionary Literals, NSDictionary , and NSMutableDictionary

初始化NSDictionary并以老方法访问其元素

不同的编程语言对大致相同的东西使用不同的术语:一个存储Value的对象,你可以用Key来查找。JavaScript通过使用对象来完成这一任务,使其变得简单,Ruby有Hash值,Python有字典。

考虑一下下面的 Python 字典定义:

importantNumbers = { 
  "Meaning of life" : 42, 
  "USS Reliant prefix code" : 16309, 
  "Single-precision pi" : 3.14159, 
  "Double-precision pi" : 3.14159265358979, 
  "Avogadro's Number" : 6.0221415E+23
}

Ruby的hash语法也是类似的:

importantNumbers = { 
    "Meaning of life" => 42,
    "USS Reliant prefix code" => 16309,
    "Single-precision pi" => 3.14159,
    "Double-precision pi" => 3.14159265358979,
    "Avogadro's Number" => 6.0221415E+23
}

如果你想用Ruby或Python访问与 "生命的意义 "这个键相关的数字,你会这样做:

importantNumbers["Meaning of life"] 

在 Objective-C 中,相应的结构是 NSDictionary 类。这里是老式的 Objective-C 等同于上面的代码。由于NSDictionary只存储对象,我们必须用新的字面语法将数字包在NSNumbers中:

NSDictionary *importantNumbers = [NSDictionary dictionaryWithObjectsAndKeys:
    @42, @"Meaning of life",
    @16309U, @"USS Reliant prefix code",
    @3.14159F, @"Single-precision pi",
    @3.14159265358979, @"Double-precision pi",
    @6.0221415E+23, @"Avogadro's Number",
    nil];

  注意,列表必须提供 dictionaryWithObjectsAndKeys:方法,先列出值,后列出键,这与其他大多数编程语言的做法相反。与 NSArray 的 arrayWithObjects:方法一样,我们必须用 nil 标记列表的结尾。

如果你觉得上面的代码有点多,那么想象一下,如果没有NSNumber字面意义,会是什么样子?

老方法:

[importantNumbers objectForKey:@"Meaning of life"]

 

初始化NSDictionary并以新方式访问其元素

幸运的是,你在XCode 4.5中得到的Objective-C为我们提供了字典字面。下面是你现在如何定义importantNumbers。

NSDictionary *importantNumbers = @{
    @"Meaning of life" : @42,
    @"USS Reliant prefix code" : @16309U,
    @"Single-precision pi" : @3.14159F,
    @"Double-precision pi" : @3.14159265358979,
    @"Avogadro's Number" : @6.0221415E+23
};

这就好多了。像JavaScript、Python和Ruby这样的语言有标准化的大括号({和})来指定字典式的集合,在Objective-C中看到这种语法是很好的。顺序也是我们所期望的:键在前,值在后。最后,不需要使用nil来终止列表。

从 NSDictionary 中访问一个值的语法也更简单了:

importantNumbers[@"Meaning of life"]

使用字典字面意义初始化NSMutableDictionary

和 NSArray 一样,NSDictionary 也不是可变的,但它有一个名字相似的可变子类。它是 NSMutableDictionary,和 NSArray 一样,你可以使用 literal 和 mutableCopy: 方法来创建一个。

NSMutableDictionary *importantNumbers = [@{
    @"Meaning of life" : @42,
    @"USS Reliant prefix code" : @16309U,
    @"Single-precision pi" : @3.14159F,
    @"Double-precision pi" : @3.14159265358979,
    @"Avogadro's Number" : @6.0221415E+23
} mutableCopy];

NSDictionary一样,你可以使用新的语法访问NSMutableDictionary的元素。

importantNumbers[@"Meaning of life"]

而且由于它是可变的,你可以进行修改。  

importantNumbers[@"Meaning of life"] = @43;
[importantNumbers setObject:@2012 forKey:@"iOS 6 launch year"];