iOS 內存管理的一點小問題

如今你們的項目應該基本都是ARC了,若是仍是MRC的話,趕忙轉換到ARC吧!最近被臨時拉過去開發iPad,因爲項目緣由,仍是使用的MRC。今天在調部分界面的時候,發現一段代碼,我怎麼看都怎麼以爲怪怪的,由於是MRC嘛!因此我內心仍是一直提醒着本身。仔細一看還真是不對,這段代碼給周圍同事看的時候,也不是每一個人都能一眼看出問題,由於你們已經習慣了ARC或者沒有在MRC下進行開發過。指針

下面我貼出相似的代碼:code

- (void)pushVc
{
    pushVC = [[UIViewController alloc] init];

    [self.navigationController pushViewController:pushVC animated:YES];
}

以上這段代碼很簡單,就是有個UIViewController類型的成員變量pushVC,而後建立一個VC賦值給他,最後push到這個頁面。可能不少人一看,這代碼就是日常本身寫的啊,都沒有出現過問題啊。若是這段代碼是在ARC下,是沒有任何問題的。可是,若是咱們的代碼是在MRC下,會出現什麼問題呢?若是經歷過MRC開發的人,確定也會以爲這邊怪怪的。至少沒有發現調用release。因爲pushVC是成員變量,因此必定程度上也迷惑了下同事。上面的代碼其實已經內存泄露了。[[UIViewController alloc] init] 這個方法建立出來的對象將不會被銷燬,一直留在內存中。爲何?這個對象建立出來的時候引用是1,而後通過push引用計數已經變成2了。當這個vc在後面被pop出來的時候,引用計數會減1,這時這個VC的引用計數仍是1。在內存中將銷燬不掉。若是這個方法被屢次調用的話,將會出現大量的這個對象在內存中。對象

下面再說一個知識點,不少人知道,可是並不必定徹底瞭解咱們的@property到底作了什麼。內存

- (void)pushVc
{
    self.pushVC = [[UIViewController alloc] init];

    [self.navigationController pushViewController:pushVC animated:YES];
}

在看這段代碼,我給成員變量賦值的方式換成了self.pushVC,這個和直接賦值有什麼區別呢?若是你調用self.pushVC進行賦值,那麼這個時候會調用系統爲咱們默認生成的setter方法。這個setter會幫咱們作內存的引用計數操做。看下系統生成的方法示例:開發

- (void)setPushVC:(UIViewController *)setPushVC
{
    [setPushVC retain];
    [pushVC release];
    pushVC = setPushVC;
}

首先,系統會將傳進來的對象引用計數加1,以後將賦值的對象引用計數減1,最後再給對象賦值。記得本身重寫setter方法的時候,必定要先將傳進來的對象作下retain操做,以後在release自己的對象。若是你代碼這樣寫的話:編譯器

- (void)setPushVC:(UIViewController *)setPushVC
{
    [pushVC release];
    [setPushVC retain];
    pushVC = setPushVC;
}

正常狀況下是沒有問題的,可是若是是本身給本身賦值的話self.pushVC = pushVC,那就有問題了。固然你能夠作下if判斷,兩個對象是否同樣,那樣也行。it

接下來看下這個代碼的正確寫法:內存管理

UIViewController *VC = [[UIViewController alloc] init];
    pushVC = [VC retain];
    [VC release];
    [self.navigationController pushViewController:VC animated:YES];
    //或者
    UIViewController *VC = [[UIViewController alloc] init];
    self.pushVC = VC
    [VC release];
    [self.navigationController pushViewController:VC animated:YES];

建議你們在MRC下使用成員變量的時候最好使用self.setter方法。有同事又提出了另外一種寫法:io

pushVC = [[[UIViewController alloc] init] autorelease];

    [self.navigationController pushViewController:pushVC animated:YES];

autorelease,可是這樣寫有個問題,一旦你使用這個關鍵字,那你就不在有這個建立對象的內存管理權,系統會在以後的某個時間,對其進行release操做。這樣也違背了用成員變量保存這個VC的意圖。編譯

總結

不少同事一眼沒有看出來,是由於咱們已經習慣了ARC,認爲=就是給對象進行了retain。在ARC下默認變量前面都有一個隱藏的__strong。在ARC下只要變量指向對象,那麼系統會咱們自動的對那個對象進行retain操做,當咱們將對象置爲nil的時候,系統會默認給咱們作release操做。

引用計數內存管理的思考方式:

  • 本身生成的對象,本身所持有
  • 非本身生成的對象,本身也恩能持有
  • 本身持有的對象再也不須要時釋放
  • 非本身持有的對象沒法釋放

當咱們使用ARC的時候,也是遵循了上面的思考方式。不要由於咱們沒有看到retain或者release而認爲管理方式變了或者不須要內存管理了。ARC看起來很簡單,由於蘋果把那些引用計數的操做代碼都交給了編譯器,因此給了咱們這種錯覺。瞭解MRC,能夠加深本身對ARC的理解。不至於讓本身被ARC給矇蔽了。

使用ARC可讓咱們的代碼更加精簡,健壯,特別是weak這個關鍵字,更是解決了野指針的問題。

相關文章
相關標籤/搜索