身为一个Coder,自己已拥有的工具,需要挖掘它们的潜力,本篇来系统梳理下 字面量这个容易被忽略的OC语法工具。
字面量这个词似乎挺陌生,但是下面的代码你一定用过:
NSLog(@"Hello world");
这里@包含的就是一个字符串的字面量,如果不用字面量,你就需要这样写:
NSString *str = [[NSString alloc] initWithCString:"Hello world" encoding:NSUTF8StringEncoding];
NSLog(@"%@", str);
繁琐不说,还很不直观。有些教程称字面量为语法糖,倒是十分写意,确实
字面量是LLVM4提供的一种简便语法,可直接使用值来声明一些OC对象
字符串的意外发现
偶然的一次失误,发现以下代码可以编译运行:
NSString *strThree = @"one,two,"@"three";
NSLog(@"%@", @"one,two,""three");
NSLog(@"%@", @"one,two,"@"three");
NSLog(@"%@", strThree);
结果输出了:
one,two,three
实际上以上代码实现了字符串的拼接,在特定场合对代码可读性有特殊作用,比如SQL语句:
[db executeUpdate:
@"CREATE TABLE Person ("
@" id INTEGER PRIMARY KEY,"
@" name TEXT NOT NULL DEFAULT '',"
@" colorName TEXT NOT NULL,"
@" taps INTEGER NOT NULL DEFAULT 0,"
@" createdTime INTEGER NOT NULL,"
@" modifiedTime INTEGER NOT NULL"
@");"
]
这样使代码清晰可读!
创建NSNumber
NSNumber *myNumber = @3;
NSNumber *yesValue = @YES;
注意: 不能把 @3 写成 @"3" ,会将数字转换为NSString,造成不可预估的类型错误。
默认情况下,数字值被当做有符号整型,小数值被当做double类型。通过加后缀的方式,转换为float型:
NSNumber *valueOfPi = @3.14F; //使用float字面量声明一个NSNumber对象
NSNumber *radius = @3U; //使用无符号integer字面量声明一个NSNumber对象
类型后缀如下表所示:
后缀 | 类型 |
---|---|
F | float |
U | unsigned int |
L | long |
LL | long long |
使用表达式
NSNumber *sum = @(1+2);
创建NSArray
NSString *str1 = @"Hello";
NSString *str2 = @"World";
NSString *str3 = @"!";
NSArray *myArray1 = [NSArray arrayWithObjects:str1, str2, str3, nil];//用旧方法创建一个新数组
NSArray *myArray2 = @[str1, str2, str3]; //使用集合字面量创建一个新数组
结合字符串和NSNumber字面量声明数组:
NSArray *strArray = @[@"Hello", @"World", @"!"];
NSArray *numArray = @[@1, @2, @3];
创建“二维”数组
OC中的二维数组实际上是嵌套的数组,利用的是数组能够存储对象,而数组本身也是一种对象这一事实。
NSArray *numArray2d = @[@[@1, @2, @3],
@[@11, @12, @13],
@[@21, @22, @23]
];
使用二维数组,强烈推荐,你可以自己尝试用 objectAtIndex 写一下相同的访问作对比
numArray2d[2][2]
创建NSDictionary
NSDictionary *dictionary2 = @{@"KEY1":@"value1",
@"KEY2":@"value2",
@"KEY3":@"value3"};
嵌套的字典声明,字面量占尽优势:
NSDictionary *dictionary = @{@"KEY1":@{@"KEY11":@"value11",
@"KEY12":@"value12",
@"KEY13":@"value13"},
@"KEY2":@"value2",
@"KEY3":@"value3"};
而“过时”的声明方法来实现一个嵌套的字典,实在过于繁琐,我再也不想那样写了。
下标访问
现在你已经知道如何方便地声明数组和字典,而字面量将赋予NSArray与传统C语言数组一样的元素访问能力,感觉释放了NSArray的小宇宙:
NSArray *array = @[@1, @2, @3, @4, @5];
int elementAt3 = array[3];
对比无字面量的方法:
NSArray *array = [NSArray arrayWithObjects:[NSNumber numberWithInt:1], [NSNumber numberWithInt:2], [NSNumber numberWithInt:3], nil];
int elementAt3 = [array objectAtIndex:3];
节省的时间和代码量堪称几何级!
而对于字典(NSDictionary),提供字符串形式的下标访问:
NSDictionary *dictionary = @{@"KEY1":@"value1",
@"KEY2":@"value2",
@"KEY3":@"value3"};
NSString strAtKey3 = dictionary[@"KEY3"];
重要提示:以上字面量声明中用到值,都不能为nil,需要用[NSNull null]代替;
另外,如果对象中有成员为nil,会立刻抛出异常,而数组的构造方法会声明一个异常长度的数组对象(arrayWithObjects遇到nil后,会将nil前的对象声明为成员,nil后的对象则被丢弃!),后者往往更难排查。所以字面量声明数组,也是排坑的不二之选。如:
NSString *str1 = @"one";
NSString *str2;
NSString *str3 = @"three";
NSArray *array = @[str1, str2, str3];
假设str2==nil,会报异常:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: ' -[__NSPlaceholderArray initWithObjects:count:]: attempt to insert nil object from objects[1]'
也由抛出的异常可见,字面量运行时实际转换成了
NSString *cArray[3] = {str1, str2, str3}; //纯C数组的初始化
NSArray *array = [NSArray arrayWithObjects:cArray count:3];
创建可变集合对象
字面量创建默认为不可变集合对象,需要可变集合对象调用mutableCopy即可:
NSMutableArray *mutableArray = [@[@1, @2, @3] mutableCopy];
字典声明类似。
转为可变集合后,也开启了下标操作的“新技能”——写操作
mutableArray[3] = @"NewValue";
mutableDictionary[@"KEY3"] = @"NewValue";