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
時,其內容都是最後被修改的內容,如此可證明記憶體的參考點是相同的,增加字串內容只是將加入的字串做個鏈結。
結論
以上這兩種方式利用範例將它表示出來,那這兩個究竟是差在哪呢?整體來說在使用上是沒差別,但以效率而言,不可變類別效率會比可變類別來的好!為什麼呢?因為不可變類別在建立時,會跟系統要一個靜態的記憶體位址,所以字串在存放時是連續的,只要從頭存放到尾,但可變類別卻是很多塊的記憶體位址所組合成的存放空間,在使用上時必需還要加上參考資料才能將完整的字串呈現,在運用上就沒有不可變類別有效率。