清楚常量字符串和一般字符串的区别

在Objective-C,经常会用到常量字符串,常量字符串和一般的字符串还是有一定区别的.本节将介绍一些常量字符串的特性,用来加强对常量字符串的理解.请看下面一段代码.

NSSting *sting1 = @"Hello";
NSSting *sting2 = @"Hello";
if (sting1 == sting2) {
    NSLog(@"They are same address");
}

对字符串常量sting1和sting2的地址值进行比较,就会发现二者竟然是相等的,产生这样的结果要归咎于编译器优化的结果.

由于常量会占用一块特殊的代码段,加载到内存是会映射到一块常量存储区,以加快访问速度,编译器在编译时发现sting1和sting2的内容是相同的常量字符串,会把它们都指向一个相同的区域,而不是在开辟出一块额外的空间.因此,它们是相同的地址值.

NSSting *sting1 = @"Hello";
NSSting *sting2 = [NSSting alloc];  NSSting *sting3 = [sting2 initWithSting:sting1];        if (sting1 == sting2) {
    NSLog(@"sting2 are not same to sting3!");
}
    if (sting1 == sting3) {
    NSLog(@"sting1 are not same to sting3!");
}

首先,申明上面这一段代码不是一段合法的代码,因此在第2行alloc之后没有立即init.虽然这种做法是非常不推荐的,但这次为了更加清晰地说明问题,不得而已为之.

通过程序比较分析,就会发现sting2和sting3的地址竟然不相等,而sting1和sting3竟然相等.通过这些可以看出,如果使用一个常量字符串来初始化另一个字符串,另一个字符串会直接通过地址赋值为常量字符串,alloc的内存也会立即释放.再看看下面这段代码:

NSSting *sting1 = [[NSSting alloc]initWithSting:@"Hello"];
[sting1 release];
[sting1 release];
[sting1 release];
NSLog("%@", sting1);

sting1经过多次release竟然还能继续访问,由此说明常量字符串不会release

在Objective-C语言中,集合是最常用的数据类型.而对与集合的访问,要优先考虑使用快速枚举.使用快速枚举,要尽可能使用枚举新的写法.

尽可使用枚举新的写法

使用Objective-C新的枚举写法,编写更简洁的代码,同时避免一些常见的陷阱.更重要的是,这些语法特性是完全向下兼容的,使用新特性编写后形成的二进制程序可以运行之前发布的OS中.

在使用枚举新的写法之前,先梳理一下最近几年来枚举类型几次功能的改进.
枚举在OS X10.5之前的版本中,如何在Objective-C中定义一个枚举类型呢?定义方法如下:

typedef enum {
ObjectiveC,
Java,
Ruby,
Python,
Erlang
}
Language;

这种写法简单明了,用起来也不复杂,但是有一个问题,就是其枚举值得数据范围是模糊的,这个数值可能非常大,可是负数,无法界定.
在OSX 10.5之后 的版本中,就可以这样写:

    enum{
    ObjectiveC,
    Java,
    Ruby,
    Python,
    Erlang
    };
    typedef NSUInteger Language;
    
这种写法的好处是,首先这个枚举的数据类型是确定的,无符号整数;其次,由于采用了NSUInteger,就可以不用考虑32位和64位的问题.但这样写所带来的问题是,数据类型和枚举常量没有显示的关联在Xcode4.4,就可以这样写枚举:

    typedef enum Language:NSUInteger {
    ObjectiveC,
        Java,
        Ruby,
        Python,
        Erlang
        }Language;

在列出枚举内容的同时绑定了枚举数据类型NSUInteger,这样带来的好处是增强了类型检查和更好的代码可读性.

当然,对于普通开发者来说,枚举类型可能不会涉及复杂的数据,使用之前的两种写法也不会用什么大问题,但还是建议使用枚举的写法,以增强现在写的代码在未来中有更强的适用性.

上面介绍了为何尽可能使用枚举新的写法,下面将介绍枚举在集合中的应用.
Objective-C和Cocoa或Cocoa Touch提供了多种方式来枚举集合的内容.虽然它可以使用传统的C循环来遍历内容,像这样:

int count = [array count];
for(int index = 0;index < count; index++) {
    id eachObject = [array objectAtIndex:index];
    ...
}

这时最好的做法是使用本节中描述的其他技术之一.

理解快速枚举

快速枚举是一种语言中用于快速安全的枚举一个集合的表达式,下面将从快速枚举的定义及其应用来分别介绍.
for...in表达式,这种快速枚举表达式是如下定义的:

for(existingItem in expression) {
    statements
}

这两种表达式中,expression 是一个遵守NSFastEnmeration协议的对象.每次循环被迭代的对象都会返回一个对象并赋给一个循环变量,同时statements 中定义的代码被执行一次.当被迭代的对象中已经没有数据可以取出时,循环变量被设为nil,如果循环在这之前被停止,那么循环变量会指向最后一次返回的值.

使用快速枚举可以很容易地枚举集合

许多集合类遵照了NSFastEnumeration协议,如Foundation中的集合类NSArray、NSDictionary和NSSet.显而易见,枚举操作可以遍历NSArray和NSSet的内容.对于其他类,相关文档会说明哪些内容会被枚举.例如,NSDictionary和NSManagedObjectModel也支持快速枚举但是NSDictionary枚举的是它的键值,NSManagedObjectModel枚举的是它的实体.

作为一个例子,可以使用快速枚举,像这样在每一个数组记录每个对象的描述:

for(id eachObject in array){
id object = dictionary[eachKey];
NSLog(@"object:%@for key:%@",object,eachKey);
}

快速枚举的行为很像一个标准C循环,这样就可以使用打破关键字来中断迭代,或继续前进到下一个元素.如果枚举有序的集合,枚举按顺序来进行.对于一个NSArray,这意味着第一次将索引为0,第二个对象在索引1处等等.如果需要跟踪当前索引,只需迭代计数,因为它们发生:

int index = 0;
    for(id eachObject in array) {
    NSLog(@"Object at index %i is:%@",index,eachObject);
    index++
    }

在快速枚举集合期间,不能变异集合,即使集合是可变的.如果从循环内,尝试添加或删除集合的对象,则会生成运行时异常.

大多数集合也支持枚举对象

也可以通过使用NSEnumerator对象枚举Cocoa和Cocoa Touch中的许多集合.例如,对于objectEnmerator 或reverseObjectEnumerator,可以查询NSArray.快速枚举可以使用这些对象,像这样:

for(id eachObject in[array reverseObjectEnumerator]) {
...
}

从此示例中,循环将按照相反的顺序来让变数可以递回取得集合的对象,所以最后一个对象将是第一个,等等.通过反复调用枚举的nextObject的方法,它也可以遍历这些内容,像这样:

id eachObject;
 while ((eachObject = [enumerator nextObject])) {
    NSLog(@"Current object is:%@",eachObject);
 }

在这个例子中,一个 while 循环用于将eachObject变量设置为每次循环的下一给对象.当没有更多的对象保留时间,nextObject方法将返回nil.评估为false的逻辑值,以使循环停止.

你可能感兴趣的:(清楚常量字符串和一般字符串的区别)