mutable VS immutable

mutable VS immutable

可變 與 不可變 類別

Objective-C在Fundation Framework中提供了 可變類別(mutable)不可變類別(immutable),依字面來說,不可變類別即是物件宣告時就給予初始值內容,其內容無法去修改,如果用方法所產生與原先不同的內容時,其方法都會將物件重新建立後再取代原先物件。

不可變類別

舉個例子來說,Java在字串中也有 StringStringBuilder 這兩種方式,以 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

這就可以證實在處理時它會重新建立新的物件,造成記憶參考的位址是不相同的。

可變類別

依照前面的做法,同樣要依序兩次加入字串dannydanny 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

印出resstr1時,其內容都是最後被修改的內容,如此可證明記憶體的參考點是相同的,增加字串內容只是將加入的字串做個鏈結。

結論

以上這兩種方式利用範例將它表示出來,那這兩個究竟是差在哪呢?整體來說在使用上是沒差別,但以效率而言,不可變類別效率會比可變類別來的好!為什麼呢?因為不可變類別在建立時,會跟系統要一個靜態的記憶體位址,所以字串在存放時是連續的,只要從頭存放到尾,但可變類別卻是很多塊的記憶體位址所組合成的存放空間,在使用上時必需還要加上參考資料才能將完整的字串呈現,在運用上就沒有不可變類別有效率。