使用Objective-C的时候,你经常会使用其中一些类型,他们就是整个基础框架。技术上讲,写Objective-C并一定要使用基础框架,但实际上经常会用到。这些类包括NSString,NSNumber,NSArray和NSDictionary。他们代表的数据结构,他们本身的名字就已经解释了。
Objective-C是知名的有很好可读性语法的语言,真的。然后,从Objective-C 1.0以来,创建一个NSString对象已经有了简单的创建方式,就是我们熟知的字符串语法,看起来这样:
NSString *someString = @"Effective Objective-C 2.0";
如果没有这种类型的语法,创建一个NSString对象就需要先调用alloc然后调用init方法,执行分配内存,然后初始化一个NSString对象的方式。幸运地,这个成为literals的语法,在最新版本的编译器种也已经支持NSNumber,NSArray,还有NSDictionary。使用Literal语法可以减小代码大小,并且让代码更容易阅读。
有时候,你需要将一个整数,浮点数,或者布尔值封装成一个对象。你需要使用能够处理多种数据类型的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 = @(xy);
使用针对数据类型的直接语法会很有用。这么做使用数据对象更清晰,正如看到的是数据定义而不是多余的语法;
数组经常被用作数据结构。在直接语法以前,你需要像下面这样创建一个数组:
NSArray *animals = [NSArray arrayWithObjects:@"cat", @"dog", @"mouse", @"badger", nil];
然后,使用直接语法仅仅需要下面这样:
NSArray *animals = @{@"cat", @"dog", @"mouse", @"badger"];
尽管这只是一个更简单的语法,但不仅仅只是一个数组。针对数组最通常的操作就是获得指定位置的对象。使用直接与饭也能更简单。通常,你要使用 objectAtIndex: 方法,
NSString *dog = [animals objectAtIndex:1];
直接语法则像下面这样:
NSString *dog = animals[1];
这被称为索引标示法,就像其他的直接语法一样,更精确,并且更容易看出来在做什么。这和其他语言种的数组按索引查找类似。
然而,使用直接语法创建数组时你需要注意一件事:如果任何一个对象是nil,那么将会抛出一个异常,因为直接语法仅仅是个将所有对象使用大括号标示的语法糖。看起来异常就像这样:
*** 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 arrayWithObjects:object1, object2, object3, nil]; NSArray *arrayB = @[object1, object2, object3];
现在考虑装一个场景:object1和object3分别指向一个合法对象,而object2为nil。使用直接语法的arrayB将会抛出一个异常。然而,arrayA将仅仅包含object1。原因就是arrayWithObjects:方法会遍历所有的参数,直到遇到nil,正如我们预期的那样。
还有个微小的不同就是直接语法更安全。比起创建一个数组,实际含有的对象比预期的要少的多,抛出一个异常并引起程序崩溃则要好的多。将nil插入数组通过是个编程错误,而异常引起的问题则要容易发现的多。
字典提供了一个键值映射的数据结构。像数组一样,字典在Objective-C中经常被用到。经常会这样创建一个字典:
NSDictionary *personData = [NSDictionary dictionaryWithObjectsAndKeys:@"Matt", @"firstName", @"Galloway", @"lastName"], [NSNumber numberWithInt:28], @"age", nil
这很容易混淆,因为顺序是值,键,值,键,循环往复。而后,换一个方式来想字典,键对应一个值更容易理解。直接语法再一次可以更清楚的表达:
NSDictionary *personData = @{@"firstName":@"Matt", @"lastName":@"Galloway", @"age":@28};
这样更准确,正如你预期的键在对象前面;同时主要例子中的数字对象,直接语法很有用。值和键豆必须是Objective-C对象,不应该存储一个整数值28;而是应该封装成一个NSNumber对象来使用。显示直接语法仅仅是多一个字母那么简单。
就像数组一样,针对字典的直接语法也同样面临一个问题,就是如果任何一个值为nil就是抛出异常。同样的原因,这也是一个好的处理方式。这就是说,dictionaryWithObjectsAndKeys:方法会在第一个nil处结束,因此有可能创建一个含有错误内容的字典,而使用直接语法则会抛出异常。
和数组一样,字典可以通过直接语法访问。原来获取指定键的值的方法如下:
NSString *lastName = [personData objectForKey:@"lastName"];
同样地,使用直接语法则这样:
NSString *lastName = personData[@"lastName"];
再一次,多余的语法将减少了,只剩下容易阅读的代码。
你可以用同样的方式通过索引获取数组中的对象或者字典中的键, 如果对象可变,你也可以设置他们。针对可变数组和字典,你需要这样设置:
[mutableArray replaceObjectAtIndex:1 withObject:@"dog"]; [mutableDictionary setObject:@"Galloway" forKey:@"lastName"];
通过索引设置只要这样:
mutableArray[1] = @"dog"; mutableDictionary[@"lastName"] = @"Galloway";
直接语法的一个小的限制就是创建的对象类型必须是Founation框架中可以找到的,否则会抛出异常。没有任何其他方式可以指定你自己的类。 如果你想创建自己定义的类,那么必须使用非直接语法创建。由于NSArray, NSDicitonary和NSNumber是类型, 他们很少被子类化,也没有必要这么做。同样,标准的实现已经足够好了。字符串可以使用自定义的类,但必须通过改变编译选项来完成。我们不鼓励这么做,除非你明白你在做的,你会经常用到NSString.
同样,就拿字符串,数组和字典来说,只有不可变的类型才可以使用直接语法。可变的类型只能通过拷贝来实现:
NSMutableArray *mutable = @[@[@1, @2, @3, @4, @5] mutalbeCopy];
尽管需要多一个方法调用,并且创建了一个新的对象,但使用直接语法带来的好处远大于这些缺点。
- 使用直接语法创建字符串,数字,数组和字典。它比使用普通方法调用更简单有效。
- 通过索引访问数组中某个位置的元素或者字典中的键。
- 使用直接语法时,视图插入nil到数组或者字典中会抛出一个异常。因此,使用确保插入的值不要是nil。