2013年10月20日 星期日

iOS-memory(1)

最近為了面試K了很多C的知識,連帶的objective c有些東西也通惹!在這邊記錄一下!

先來看段C的link list code:

void insertNodeToList(linkNode *list, int data){
   
   linkNode newNode = (linkNode)malloc(sizeof(Node));
   newNode -> data = data;
   newNode -> next = NULL;
   
   linkNode current = *list;
   linkNode previous = NULL;
   if(*list==NULL){
      *list = newNode;
   }   
   else{
      while(current != NULL){
         previous = current;
         current = current -> next;
      }   
      previous -> next = newNode;
   }   
}

上面這段code是小時候剛學資料結構的時候常常會寫到的東西,比較重要的幾個pointer:

//alloc一塊memory並讓newNode 這個pointer指著
linkNode newNode = (linkNode)malloc(sizeof(Node));
//指著link list 的開頭
linkNode current = *list;
linkNode previous = NULL;

上面pointer一開始的狀態是先alloc一塊memory給newNode這個pointer指著(注意如果沒有pointer指著這塊記憶體的話,會發生memory leak的問題),然後current這個pointer指著*list這個pointer,previous只是在traversal的時候需要記住目前的pointer位置,如下圖:

此時如果把newNode插入到link list最尾端,如下圖

上面這段過程小時候應該超級熟悉的->link list插入,只是小時候常常只是照摳程式碼,然後可以動就可以惹,完全忽略為什麼link list用完要free啊之類的小細節,看著大家這樣寫就跟著這樣寫,考試考過就OK的想法,結果現在留了一對債要還QQ!回歸正題,再來看一段free的code

void freeList(linkNode *list){

   linkNode current = *list;

   while(current != NULL){
      linkNode tmp = current;
      current = current -> next;
      free(tmp);
   }   
   *list = NULL;
}

這段code說明把link list給全部free掉釋放記憶體,注意的是最後一行

*list = NULL;

如果沒有這行的話*list依舊指著該記憶體,只是不知道在指到的東西沒有意義(dangling)。看完這兩段小小的復習,大概可以知道pointer到底在做什麼,其實pointer的概念不難,難的是不知道用在哪裡,以及代表意義是什麼,其實總結一下pointer的功能:

用來指向某個已經分配記憶體的位址

復習完後整理一下大概會發生的bug scenario:

1. 如果alloc一塊memory給linkNode newNode,緊接這newNode = NULL,就會發生memory leak,導致這段記憶體區塊無法使用,如下圖

2. 如果同時有兩個pointer指著同一個memory記憶體位置,只要其中一個pointer free掉之後,另外一個pointer也不再擁有memory

接下來的部分是objectiv-c得記憶體管理,平常都用ARC的方式在寫code,ARC實在是很方便,只要我有一個strong的指標指著物件,該物間就不會被摧毀掉,直到該物間沒有任何的pointer指著他時,該物件才會被摧毀掉。但是如果是手動控管記憶體的話,可就沒有這麼方便惹,完完全全要回到以前寫c的時候,用人工去控制記憶體的分配,老實說實在是有夠麻煩,雖然現在大部分都用ARC,不過偶而還是會碰到iOS5以前的code,所以還是要瞭解一下,剛好最近投了一些APP的公司,東估一下西估一下,把理解的部分記下來。

先從retain和release說起:

NSString *str = [[NSString alloc]init];
NSString *str2 = str;

上面這段code代表str和str2同時指向同一塊記憶體(同一個物件),如果此時把str給摧毀掉,就會發生bug scenario2的情況,此時該怎麼辦呢?就要靠retain這個method惹,這個意思是我們需要對記憶體區塊做"保留"幾次,如果某個pointer被release掉了,而iOS說明如果該記憶體(物件)的retain count=0的時候,會自動摧毀該物件,導致str2所指的物件也跟著被摧毀,就可能會發生常常很討厭看到記憶體問題bug。

此時解決的辦法就是用

[str retain];

上面這一行code會修正bug scenario2,當str指到NULL或是其他物件時,str2所指向的物件依舊沒有被摧毀,效果如下圖:

知道retain和release之後,接下來就要來看常常會宣告的@property與@synthesis惹,估狗後得到的結論是如下:

  1. @property為宣告setter和getter
  2. 在MRC的scenario會用到的關鍵字:assign, retain, readwrite,readonly, copy, nonatomic

readwrite和readonly的概念很簡單,就是如果我宣告readonly的話,只會時作出getter,而readwrite的話會objective-c compiler會自動幫忙時作出getter和setter,在預設直上是設定readwrite。

assign只是單存的把指標指向該記憶體,就像上面link list插入時我們宣告的current一樣,如果把另外一個pointer給指到其他位址的話,一樣會造成scenario 2的問題,概念上就是沒有retain的意思,所以如果採用retain的話,就可以把scenario 2的bug給修正掉。

nonatomic,atomic是跟執行續有關的關鍵字,基本上盡量用nonatomic會比較好一點,也可以增加執行效率。以下就是常看到的:

@property(nonatomic,retain) UIWindow *window;

總結,在objective-c的記憶體管理上,概念幾乎都c相同,最近用功研讀了一下,發現不要把objective-c看成另外一種語言,其實概念幾乎都跟c相同,只是語法上比較奇怪一點,很多東西用c的想法幾乎都可以通,剩至可以用c來實做每一個method,只是很土炮,每個功能都要自己實作,好在有在公司接案寫App,讓我越來越理解objective-c的想法,個人認為objective-c基本上就是c語言+apple提供的framework+好用的物件概念吧!

參考資料:

  1. Objective-C中的@property和@synthesize用法
  2. Objective-C隨手筆記 I:Property

沒有留言:

張貼留言