现在的位置: 首页 > 综合 > 正文

Effective Object-C 2.0 第一章(条目3)

2018年03月22日 ⁄ 综合 ⁄ 共 3711字 ⁄ 字号 评论关闭

条目3:选用字面型语法而不是等价的方法

       使用OC的过程中,有些类是你经常遇到的。他们都是Foundation框架的一部分。虽然技术上来说,你并不一定要用Foundation去写OC代码,但是实践中,你通常会用它。例如NSString,NSArray,NSDictionary。每一种类型代表的数据结构是不言自明的。

OC以冗余语法而有名,这是真的。可是,自从OC1.0开始,已经很多简便的方法进行NSString对象的创建。那通常被叫做string字面值,一般看起来如下:

NSString *someString = @”Effective Object-C2.0”;

如果没有这种语法,创建NSString对象需要alloc和init进行分配和初始化。幸运的是,这种字面值语法已经被最近的编译器版本中被扩展到NSNumber,NSArray,NSDictionary中。使用字面值语法会减少源代码的大小同时使代码更易读。

字面值数字

       有时,你需要封装int,float等到一个OC对象。你通过NSNumber进行这个操作,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 =

[NSArrayarrayWithObjects:@"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 uncaughtexception

'NSInvalidArgumentException', reason: '***

-[__NSPlaceholderArrayinitWithObjects:count:]: attempt to

insert nil object from objects[0]'

       这也带来了一个常见的问题,考虑下面两个创建数组的方式:

id object1 = /* ... */;

id object2 = /* ... */;

id object3 = /* ... */;

NSArray *arrayA = [NSArrayarrayWithObjects:

object1, object2, object3, nil];

NSArray *arrayB = @[object1, object2,object3];

现在考虑一种情况,object1和object3是有效的Oc对象,object2是nil。字面值语法进行创建arrayB将会抛出异常。但是arrayA仍然可以被创建并仅仅包含object1对象。原因是arrayWithObjects方法扫描参数直到nil为止,当然这并不是我们想要的。

这种微妙的不同使得字面值更安全。抛出异常并引起崩溃往往比使一个数组有比我们期望的元素更少这种情况更好。程序员的错误很可能使nil插入到了数组里面,而通过抛出异常使得这类bug很容易被发现。

字面值词典

词典提供了一种可以添加key-value的map类型的数据结构。如数组一样,词典也被广泛使用于OC代码。过去通常通过以下方式创建词典:

NSDictionary *personData =

[NSDictionary dictionaryWithObjectsAndKeys:

@"Matt", @"firstName",

@"Galloway",@"lastName",

[NSNumber numberWithInt:28],@"age",

nil];

这看起来很让人迷惑,因为顺序时<object>, <key>, <object>, <key>的方式。可是你通常以另外的一种key-value的方式来看待词典,因此它的可读性不好。可是字面值再一次使其更简单明白:

NSDictionary *personData =

@{@"firstName" : @"Matt",

@"lastName" : @"Galloway",

@"age" : @28};

    这看起来更简洁,正如你想看到的那样,key在value之前。同样需要注意到字面值数字的使用是非常有用的。Key和value必须是OC对象,因此你不可以将int 28存入到词典中,可是你可以使用NSNumber进行封装。使用字面值语法意味着你仅仅需要多写一个@字符即可。

像数组那样,词典类型的字面值语法在遇到value为nil的情况会抛出异常。可是,基于同样的原因,这样更好。它意味着程序会抛出异常,而不是创建一个缺少value的对象。

同样和数组类似,字典也可以通过字面值语法获取。古老的获取指定key的value方式如下:

NSString *lastName = [personDataobjectForKey:@"lastName"];

等价的字面值语法如下:

NSString *lastName = personData[@"lastName"];

再一次,通过易读的代码,冗长的语法被避免了。

可变数组和词典

同样的思想,你可以通过下标访问数组和词典,那么当它们是可变的话你也可以通过下标设置它们的值。通常的设置可变数组和词典的方法看起来如下:

[mutableArray replaceObjectAtIndex:1withObject:@"dog"];

[mutableDictionarysetObject:@"Galloway" forKey:@"lastName"];

通过下标设置看来如下:

mutableArray[1] = @"dog";

mutableDictionary[@"lastName"] =@"Galloway";

限制

使用字面值语法的一个小的限制是除了string之外,要创建的对象必须是Foundation框架中的类。没有办法创建你自己的个性化子类。如果你需要创建个性化子类的对象,你需要使用非字面值语法。可是,由于NSArray, NSDictionary, 和 NSNumber 是类簇(查看条目9),因此对它们进行子类化是很不寻常的,它们很少被子类化。当然,标准的实现通常是足够的。Strings可以进行个性化,但是它必须通过一个编译选项才可以被改变。但是使用这个选项并不被建议使用,除非你确切的明白你在做什么。一般情况下,你总是会使用NSString。

同样需要注意的是,字符串,数组和词典只能使用字面值语法创建不可变的对象。如果你想创建可变的对象,需要如下调用mutable copy方法:

NSMutableArray *mutable = [@[@1, @2, @3,@4, @5] mutableCopy];

    这添加了一个额外的方法调用,一个额外的对象被创建了,但是使用字面值语法的好处可以弥补这些缺点。

要记住的

l  使用字面值语法进行string,number,array和dictionary的创建。这种方式比使用通常的方式更清楚明白。

l  通过下标访问数组或者词典。

l  使用字面值语法向数组或者词典中插入nil对象会抛出异常。因此,确保要插入的对象不是nil。

抱歉!评论已关闭.