文章出處

讀前小提示:對于深淺復制有一個清楚的了解,對于學習oc的朋友來說,至關重要。那么首先,我們要明白深淺復制是如何定義的呢。這里為了便于朋友們理解,定義如下。


   淺 復 :在復制操作時,對于被復制的對象的每一層復制都是指針復制。

   深 復 :在復制操作時,對于被復制的對象至少有一層復制是對象復制。

   完全復制:在復制操作時,對于被復制的對象的每一層復制都是對象復制。


        注:1在復制操作時,對于對象有n層是對象復制,我們可稱作n級深復制,此處n應大于等于1

              2對于完全復制如何實現(目前通用的辦法是:迭代法和歸檔),這里后續是否添加視情況而定

              暫時不做講解。

          3、指針復制俗稱指針拷貝,對象復制也俗稱內容拷貝。

          4、一般來講,

                 淺層復制:復制引用對象的指針。

 

               深層復制:復制引用對象內容。
            這種定義在多層復制的時候,就顯得模糊。所以本文定義與它并不矛盾。
            反而是對它的進一步理解和說明。           


retain:始終是淺復制。引用計數每次加一。返回對象是否可變與被復制的對象保持一致。


copy:對于可變對象為深復制,引用計數不改變;對于不可變對象是淺復制,

         引用計數每次加一。始終返回一個不可變對象。


mutableCopy:始終是深復制,引用計數不改變。始終返回一個可變對象。


不可變對象:值發生改變,其內存首地址隨之改變。

   可變對象:無論值是否改變,其內存首地址都不隨之改變。

   引用計數:為了讓使用者清楚的知道,該對象有多少個擁有者(即有多少個指針指向同一內存地址)。

 

 最近有一個好朋友問我,什么時候用到深淺復制呢?那么我就把我所總結的一些分享給大家,希望能幫助你們更好的理解深淺復制!


那么先讓我們來看一看下邊數組類型的轉換

1、不可變對象→可變對象的轉換:

       NSArray *array1= [NSArray arrayWithObjects:@"a",@"b",@"c",@"d",nil];

       NSMutableArray  *str2=[array1 mutableCopy];

2、可變對象→不可變對象的轉換:

    NSMutableArray *array2   = [NSMutableArray arrayWithObjects:@"aa",@"bb",@"cc",@"dd",nil];

       NSArray *array1= array2    Copy];

3、可變對象→可變對象的轉換(不同指針變量指向不同的內存地址)

       NSMutableArray *array1= [NSMutableArray arrayWithObjects:@"a",@"b",@"c",@"d",nil];

       NSMutableArray  *str2=[array1 mutableCopy];

通過上邊的兩個例子,我們可輕松的將一個對象在可變和不可變之間轉換,并且這里不用考慮內存使用原則(即引用計數的問題)。沒錯,這就是深拷貝的魅力了。

4、同類型對象之間的指針復制(不同指針變量指向同一塊內存地址):

  a、

   NSMutableString *str1=[NSMutableString stringWithString:@"two day"];

   NSMutableString *str2=[str1   retain];

   [str1  release];

  b、

   NSArray *array1= [NSArray arrayWithObjects:@"a",@"b",@"c",@"d",nil];

   NSArray  *str2=[array1 Copy];

   [array1 release];

 

   通俗的講,多個指針同時指向同一塊內存區域,那么這些個指針同時擁有對該內存區的所有權。所有權的瓜分過程,這時候就要用到淺拷貝了。

則簡化為:

問:什么時候用到深淺拷貝?

答:深拷貝是在要將一個對象從可變(不可變)轉為不可變(可變)或者將一個對象內容克隆一份時用到;

     淺拷貝是在要復制一個對象的指針時用到。


 

親愛的讀者朋友,下面是我用于驗證的詳細代碼。對于驗證還能得出什么結論,我希望朋友們能自己多多發掘一下。這里只做以上幾點總結。對于本文有任何疑問請與我聯系,歡迎指出本文不足的地方,謝謝!

 #import<Foundation/Foundation.h>

int main (int argc, const char * argv[])

{

    @autoreleasepool {

 

    ===========================第一種:非容器類不可變對象==================

  

        NSString *str1=@"one day";

        

          printf("\n初始化賦值引用計數為::::%lu",str1.retainCount);

        NSString *strCopy1=[str1 retain];

          printf("\n繼續retain引用計數為:::%lu",str1.retainCount);

        NSString *strCopy2=[str1 copy];

          printf("\n繼續copy后引用計數為::::%lu",str1.retainCount);

        NSString *strCopy3=[str1 mutableCopy];

                printf("\n繼續mutableCopy后為:::%lu\n",str1.retainCount);

        

        printf("\n非容器類不可變對象\n原始地址::::::::::%p",str1);

        printf("\nretain復制::::::::%p",strCopy1);

        printf("\ncopy復制::::::::::%p",strCopy2);

        printf("\nmutableCopy復制:::%p",strCopy3);

    //這里說明該類型不存在引用計數的概念

  // 初始化賦值引用計數為:18446744073709551615

  // 繼續retain引用計數為:18446744073709551615

  // 繼續copy后引用計數為:18446744073709551615

  // 繼續mutableCopy后為:18446744073709551615

 小提示:這里很多人都說是賦值,所以就好解釋這里沒引用計數的概念。而且也能解釋為什么

         NSString *strCopy2=[str1 copy];

         NSMutableString  *strCopy2=[str1 copy]; 

         這樣都不會報錯的原因了。那既然只是簡單賦值為什么要這么麻煩呢,直接

         NSString *strCopy2=*str1;

         NSMutableString  *strCopy2=*str1;

         其實大家都看出來了,這里是指針變量,只存在“指針的復制”,

         跟賦值概念完全不同,雖然這里看起來很像。

         原來該類型是字符串常量時,系統會為我們優化,聲明了多個字符串,

              但是都是常量,且內容相等,那么系統就只為我們申請一塊空間。

  疑問: 深復制=淺復制+賦值嗎? 

         賦值過程:輸入數據→寄存器處理→開辟內存→寫入數據。

         一次深復制,可以得到被復制對象指針,并進行一次賦值操作。

   //非容器類不可變對象

   //原始地址::::::::::0x1000033d0

   //retain復制::::::::0x1000033d0//淺復制

   //copy復制::::::::::0x1000033d0//淺復制

   //mutableCopy復制:::0x10010c420//深復制

   

      printf("\n");

 


 ==============================第二種:容器類不可變對象=================


    

   NSArray *array1= [NSArray arrayWithObjects:@"a",@"b",@"c",@"d",nil];

        

          printf("\n初始化賦值引用計數為::::::::::::%lu",array1.retainCount);

        NSArray *arrayCopy1 = [array1 retain];

          printf("\n繼續retain后引用計數為:::::::::%lu",array1.retainCount);

        NSArray *arrayCopy2 = [array1 copy];

          printf("\n繼續copy后引用計數為:::::::::::%lu",array1.retainCount);

        NSArray *arrayCopy3 = [array1 mutableCopy];

          printf("\n繼續mutableCopy后引用計數為::::%lu\n",array1.retainCount);

        

    printf("\n容器類不可變數組\n原始地址::::::::::%p\t\t%p",array1,[array1 objectAtIndex:1]);

        printf("\nretain復制::::::::%p\t%p",arrayCopy1,[arrayCopy1 objectAtIndex:1]);

        printf("\ncopy復制::::::::::%p\t%p",arrayCopy2,[arrayCopy2 objectAtIndex:1]);

        printf("\nmutableCopy復制:::%p\t%p",arrayCopy3,[arrayCopy3 objectAtIndex:1]);

        

   

    //初始化賦值引用計數為::::::::::::1

    //繼續retain后引用計數為:::::::::2

    //繼續copy后引用計數為:::::::::::3

    //繼續mutableCopy后引用計數為::::3

    //容器類不可變數組

    //原始地址::::::::::0x10010c6b0 0x100003410

    //retain復制::::::::0x10010c6b0 0x100003410//淺復制

    //copy復制::::::::::0x10010c6b0 0x100003410//淺復制

    //mutableCopy復制:::0x10010c760 0x100003410//深復制

    

        printf("\n");

 

 

 

 ===============第三種:非容器類可變對象==================


      

 NSMutableString *str2=[NSMutableString stringWithString:@"two day"];

        

          printf("\n初始化賦值引用計數為::::::::::::%lu",str2.retainCount);

        NSMutableString *strCpy1=[str2 retain];

          printf("\n繼續retain后引用計數為:::::::::%lu",str2.retainCount);

        NSMutableString *strCpy2=[str2 copy];

          printf("\n繼續copy后引用計數為:::::::::::%lu",str2.retainCount);

        NSMutableString *strCpy3=[str2 mutableCopy];

                printf("\n繼續mutableCopy后引用計數為::::%lu\n",str2.retainCount);

        

        printf("\n非容器類可變對象\n原始地址::::::::::%p",str2);

        printf("\nretin復制::::::::%p",strCpy1);

        printf("\ncopy復制::::::::::%p",strCpy2);

        printf("\nmutableCopy復制:::%p",strCpy3);

       

 

         //初始化賦值引用計數為::::::::::::1

         //繼續retain后引用計數為:::::::::2

         //繼續copy后引用計數為:::::::::::2

         //繼續mutableCopy后引用計數為::::2

         //非容器類可變對象

         //原始地址::::::::::0x10010c560

         //retain復制::::::::0x10010c560//淺復制

         //copy復制::::::::::0x100102720//深復制

       //mutableCopy復制:::0x10010c880//深復制

         

        printf("\n");

 

 

 

 =========================第四種:容器類可變對象======================


 

 NSMutableArray *array2   = [NSMutableArray arrayWithObjects:@"aa",@"bb",@"cc",@"dd",nil];

        

         printf("\n初始化賦值引用計數為::::::::::%lu",array2.retainCount);

       NSMutableArray *arrayCpy1 = [array2 retain];

         printf("\n繼續retain后引用計數為:::::::%lu",array2.retainCount);

       NSMutableArray *arrayCpy2=[array2 copy];

         printf("\n繼續copy后引用計數為:::::::::%lu",array2.retainCount);

       NSMutableArray *arrayCpy3 = [array2 mutableCopy];

         printf("\n繼續mutableCopy后引用計數為::%lu\n",array2.retainCount);

        

       printf("\n容器類可變數組\n原始地址:::::::::::%p\t%p",array2,[array2 objectAtIndex:1]);

       printf("\nretain復制:::::::::%p\t%p",arrayCpy1,[arrayCpy1 objectAtIndex:1]);

       printf("\ncopy復制:::::::::::%p\t%p",arrayCpy2,[arrayCpy2 objectAtIndex:1]);

       printf("\nnmutableCopy復制:::%p\t%p",arrayCpy3,[arrayCpy3 objectAtIndex:1]);

       

        

         //初始化賦值引用計數為::::::::::1

         //繼續retain后引用計數為:::::::2

         //繼續copy后引用計數為:::::::::2

         //繼續mutableCopy后引用計數為::2

         //容器類可變數組

         //原始地址:::::::::::0x10010e6c0 0x1000034b0

         //retain復制:::::::::0x10010e6c0 0x1000034b0//淺復制

         //copy復制:::::::::::0x10010e790 0x1000034b0//深復制

         //nmutableCopy復制:::0x10010e7c0 0x1000034b0//深復制

         

        

    }

    return 0;

}

 

 

 


文章列表


不含病毒。www.avast.com
arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()