多用字面量语法,少用与之等价的方法
字面数值
有时需要把整数、浮点数、布尔值封入Objective-C对象中。这种情况下可以用NSNumber类,该类可处理多种类型的数值。若是不用字面量,那么就需要按下述方式创建实例:
- NSNumber *someNumber = [NSNumber numberWithInt:1];
上面这行代码创建了一个数字,将其值设为整数1。然而使用字面量能令代码更为整洁:
- NSNumber *someNumber = @1;
大家可以看到,字面量语法更为精简。不过它还有很多好处。能够以NSNumber实例表示的所有数据类型都可使用该语法。例如:
- NSNumber *intNumber = @1;
- NSNumber *floatNumber = @2.5f;
- NSNumber *doubleNumber = @3.14159;
- NSNumber *boolNumber = @YES;
- NSNumber *charNumber = @'a';
字面量语法也适用于下述表达式:
- int x = 5;
- float y = 6.32f;
- NSNumber *expressionNumber = @(x * y);
以字面量来表示数值十分有用。这样做可以令NSNumber对象变得整洁,因为声明中只包含数值,而没有多余的语法成分。
字面量数组
- NSArray *animals = @[@"cat", @"dog", @"mouse", @"badger"];
- NSString *dog = animals[1];
不过,用字面量语法创建数组时要注意,若数组元素对象中有nil,则会抛出异常,因为字面量语法实际上只是一种“语法糖”(syntactic sugar),其效果等于是先创建了一个数组,然后把方括号内的所有对象都加到这个数组中。抛出的异常会是这样:
- *** Terminating app due to uncaught exception
- 'NSInvalidArgumentException', reason: '***
- -[__NSPlaceholderArray initWithObjects:count:]: attempt to
- insert nil object from objects[0]'
- id object1 = /* ... */;
- id object2 = /* ... */;
- id object3 = /* ... */;
- NSArray *arrayA = [NSArray array WithObjects:
- object1, object2, object3, nil];
- NSArray *arrayB = @[object1, object2, object3];
如果object1与object3都指向了有效的Objective-C对象,而object2是nil,那么会出现什么情况呢?按字面量语法创建数组arrayB时会抛出异常。arrayA虽然能创建出来,但是其中却只含有object1一个对象。原因在于,“arrayWithObjects:”方法会依次处理各个参数,直到发现nil为止,由于object2是nil,所以该方法会提前结束。
这个微妙的差别表明,使用字面量语法更为安全。抛出异常令应用程序终止执行,这比创建好数组之后才发现元素个数少了要好。向数组中插入nil通常说明程序有错,而通过异常可以更快地发现这个错误。
- NSDictionary *personData =
- @{@"firstName" : @"Matt",
- @"lastName" : @"Galloway",
- @"age" : @28};
字典也可以像数组那样用字面量语法访问。按照特定键访问其值的传统做法是:
- NSString *lastName = [personData objectForKey:@"lastName"];
与之等效的字面量语法则是:
- NSString *lastName = personData[@"lastName"];
可变数组与字典
通过取下标操作,可以访问数组中某个下标或字典中某个键所对应的元素。如果数组与字典对象是可变的(mutable),那么也能通过下标修改其中的元素值。修改可变数组与字典内容的标准做法是:
- [mutableArray replaceObjectAtIndex:1 withObject:@"dog"];
- [mutableDictionary setObject:@"Galloway"forKey:@"lastName"];
若换用取下标操作来写,则是:
- mutableArray[1] = @"dog";
- mutableDictionary[@"lastName"] = @"Galloway";
局限性
字面量语法有个小小的限制,就是除了字符串以外,所创建出来的对象必须属于Foundation框架才行。如果自定义了这些类的子类,则无法用字面量语法创建其对象。要想创建自定义子类的实例,必须采用“非字面量语法”(nonliteral syntax)。然而,由于NSArray、NSDictionary、NSNumber都是业已定型的“子族”(class cluster,参见第9条),因此很少有人会从其中自定义子类,真要那样做也比较麻烦。而且一般来说,标准的实现已经很好了,无须再改动。创建字符串时可以使用自定义的子类,然而必须要修改编译器的选项才行。除非你明白这样做的后果,否则不鼓励使用此选项,用NSString就足够了。
使用字面量语法创建出来的字符串、数组、字典对象都是不可变的(immutable)。若想要可变版本的对象,则需复制一份:
NSMutableArray *mutable = [@[@1, @2, @3, @4, @5]mutableCopy];
这么做会多调用一个方法,而且还要再创建一个对象,不过使用字面量语法所带来的好处还是多于上述缺点的。