mutable VS immutable
可变 与 不可变 类别
Objective-C在Fundation Framework中提供了 可变类别(mutable) 与 不可变类别(immutable),依字面来说,不可变类别即是物件宣告时就给予初始值内容,其内容无法去修改,如果用方法所产生与原先不同的内容时,其方法都会将物件重新建立后再取代原先物件。
不可变类别
举个例子来说,Java在字串中也有 String 与 StringBuilder 这两种方式,以 StringBuilder 就是指可变类别(mutable),下面以NSString
例子来看一下不可变类别:
//-----------start----------- NSString *str = @"danny"; NSLog(@"%@",str); str = [str stringByAppendingString:@" is danny"]; NSLog(@"%@",str); //------------end------------
程式中看的出来第一次初始值为danny
,之后再将它加入is danny
,但在不可变的底层来说:
- 第一次建立
danny
指向str - 第二次建立
danny is danny
指向str并删除第一次建立的danny
所以就会是这样:
//-----------start----------- NSString *str = @"danny"; NSLog(@"%@",str); str = @"danny is danny"; NSLog(@"%@",str); //------------end------------
要如何证明呢?
//-----------start----------- NSString *str1 = @"This is string A"; NSString *res; res=str1; str1 = [str1 stringByAppendingString:@" This is string B"]; NSLog(@"res=%@",res); NSLog(@"str1=%@",str1); //------------end------------
如果res
等于str1
那接下来如果增加str1
的内容时如果是同一个记忆体,那印出这2个变数值应该会相同,但印出来的结果却:
2014-02-20 18:06:27.694 test1[46806:303] res=This is string A 2014-02-20 18:06:27.696 test1[46806:303] str1=This is string A This is string B
这就可以证实在处理时它会重新建立新的物件,造成记忆参考的位址是不相同的。
可变类别
依照前面的做法,同样要依序两次加入字串danny
与danny is danny
可变类别程式则是:
//-----------start----------- NSMutableString *mstr = [NSMutableString stringWithString:@"danny"]; NSLog(@"%@",mstr); [mstr appendString:@" is danny"]; NSLog(@"%@",mstr); //------------end------------
可变类别会将2次的字串利用链结的方式将2个字串绑定:
- 第一次建立
danny
指向mstr - 第二次建立
is danny
并与danny
都指向mstr - 最终mstr为
danny
+is danny
在记忆体分配来说,会先分配一组danny
,再分配第二组is danny
,当我们要印出来时就会根据链结关系将完整的字串印出来。
这里要证明它加入新的字串内容时,参考的记忆体位址是一样的:
//-----------start----------- NSMutableString *str1 = [NSMutableString stringWithString:@"This is string A"]; NSMutableString *res; res=str1; [str1 appendString:@" This is string B"]; NSLog(@"res=%@",res); NSLog(@"str1=%@",str1); //------------end------------
输出结果: 2014-02-20 18:49:07.174 test1[47236:303] res=This is string A This is string B 2014-02-20 18:49:07.176 test1[47236:303] str1=This is string A This is string B
印出res
与str1
时,其内容都是最后被修改的内容,如此可证明记忆体的参考点是相同的,增加字串内容只是将加入的字串做个链结。
结论
以上这两种方式利用范例将它表示出来,那这两个究竟是差在哪呢?整体来说在使用上是没差别,但以效率而言,不可变类别效率会比可变类别来的好!为什么呢?因为不可变类别在建立时,会跟系统要一个静态的记忆体位址,所以字串在存放时是连续的,只要从头存放到尾,但可变类别却是很多块的记忆体位址所组合成的存放空间,在使用上时必需还要加上参考资料才能将完整的字串呈现,在运用上就没有不可变类别有效率。