Mutable strings 可变字符串

还记得我们之前提到,关于房子和路标的例子吗?房子是不可变的,但你可以改变路标的指向。在这里 NSString 是一个不可变的,但是要记住,它并不是一个常量。

和 Swift 不同的是,Objective-C 里可变对象和不可变对象之间,没有自己的语言区分构造,要判断一个对象是否可变,可以去看它的名字。NSString 是不可变的,而 NSMutableString 是可变的。

温馨提示,就算你乱用这两个类,Xcode 也不会报错,他只是会「提示」你(译者注:也就是黄色三角的小叹号,依然可以进行编译)。所以我希望,你能把 Xcode 里的「提示」当做「错误」来思考。

请看下面的代码:

NSMutableString *mutable = @"Hello";

这样写代码是会报错的,再提一下,请把Xcode 里的「提示」当做「错误」来思考。因为你创建了一个保存可变字符串的变量,然后将一个不可变的字符串赋值给了他。 @"..." 这个符号,它意味着创建了一个 NSString 。所以这种做法就是在一个装可变对象的容器里面,放了一个不可变对象。从技术的角度来看,只要你不改变这个字符串的值,这行代码也没什么问题,但这是一个很差的代码习惯。

但如果反过来,把一个可变字符串放到一个不可变字符串的容器里面,就是一个对代码安全来讲很好的习惯。这就相当于它的不可变属性是可变属性的一个子集。我所谓的「技术安全层面」,意思是如果你把一个可变的字符串放在了一个不可变的字符串容器里面,那么这个「不可变」并不是真正的不可变,只是你不能轻易地改变它,这就加固了你的代码。我们会在后面章节进一步讨论这件事。

(译者注:这一段讲得好绕,我理解的是,上一种做法是类似于一个可长可短可圆可方的杯子,但是里面只能倒水,倒了别的东西杯子就碎了。如果只喝水是无所谓的,但要改要喝的东西就不行了。而第二种做法是给一个圆柱形的不锈钢杯子,就这么大这么宽不能变了,但是喝什么都可以。我们的目的还是喝各种各样的饮料,所以显然第二种写法更优。)

如果你想要创建一个可变的字符串,有以下两种方法:第一种是创建一个现有的字符串的备份,第二种是用 NSMutableString 的初始化器来创建。我们先看第一种方法:

NSString *hello = [@"Hello" mutableCopy];

你也可以 NSString 类似的模板来创建:

NSString *hello = [NSMutableString stringWithFormat:@"..."];

stringWithCapacity 是一个非常棒的初始化器,它可以让系统知道,你所这个字符串最多可以占据多大的内存空间。也就是说,字符串的大小达到了设定的阈值时,系统就不再分配内存给它了。比如说下面这段代码,就告诉了系统我们想要为这个字符串提供4096个字符大小的内存空间:

NSString *longString = [NSMutableString stringWithCapacity:4096];

当你创建好了可变字符串之后,就可以用 setString 这个方法来修改它的内容,或者你也可以用 NSMutableString 自带的一些方法。举个例子,NSString 的 stringByReplacingOccurrencesofString 方法在这里变成了 "replaceOccurrencesOfString",stringByAppendingString 变成了 "appendString"。变化原因是,我们不再修改字符串的指针,而是直接修改字符串。

比如下面的这段代码,我们就创建了一个可以修改的字符串,然后修改它,并且把新的值打印了出来。

NSMutableString *first = [@"My string" mutableCopy];
[first setString:@"Something else"];
NSLog(@"%@", first);

还记得我上面说过什么吗?不要把 NSMutableString 当成 NSString 来使用,下面这段代码就可以告诉你为什么不要这样做:

NSMutableString *first = [@"My string" mutableCopy];
NSString *second = first;
[first setString:@"Something else"];
NSLog(@"%@", second);

控制台里面打印出来的是 "Something else" ,就算我们没有在字面上修改字符串。但是系统在背后确确实实就是做了修改。

这种不确定性是相当危险的,绝大多数的程序员会采用备份一个 NSString 的方式来解决:

NSString *second = [first copy];

用这种方式,second 的值就不会被改动。

results matching ""

    No results matching ""