天天看點

OC-深淺複制

【OC學習-26】對象的淺拷貝和深拷貝——關鍵在于屬性是否可被拷貝

對象的拷貝分為淺拷貝和深拷貝,

淺拷貝就是隻拷貝對象,但是屬性不拷貝,拷貝出來的對象和原來的對象共用屬性,即指向同一個屬性位址。

深拷貝則相當于不僅拷貝了一個對象還拷貝了它的屬性,即完全是兩個東西,隻不過内容相同而已。

拷貝用到協定,如果這個類建立對象後,這個對象要被拷貝,那麼這個類就需要用到拷貝協定,分兩種:<NSCopying>和<NSMutableCopying>相當于一個是拷貝,另一個是拷貝後可修改。

(1)淺拷貝的案例。有一個Person類,它建立一個person1對象後,用person1再拷貝一個person2出來。

//Person類的Person.h檔案
#import <Foundation/Foundation.h>
//因為這個類要支援拷貝,是以需要引入拷貝協定,有兩種,後一種拷貝後可修改
@interface Person : NSObject<NSCopying,NSMutableCopying>
@property(nonatomic,copy) NSString* name;
@property(nonatomic,retain) NSNumber* age;
@end      
//這是Person.m檔案
#import "Person.h"
@implementation Person
//這是系統函數,可以直接拷貝過來
- (id)copyWithZone:(NSZone *)zone{
  Person *person=[[[self class]allocWithZone:zone]init]; //預設格式
  person.name=_name; //淺拷貝就是直接指派即可
  person.age=_age;  //淺拷貝就是直接指派即可
  return person;
}
@end      
//main.m檔案
#import <Foundation/Foundation.h>
#import "Person.h"//記得引入頭檔案
int main(int argc, const char * argv[])
{
  @autoreleasepool {
    Person *person1=[[Person alloc]init];
    person1.name=@"jack";
    person1.age=@18;
    Person *person2=[person1 copy];
    NSLog(@"%p,%p",person1,person2);//輸入兩個對象位址,不同
    NSLog(@"%p,%p",person1.age,person2.age);//輸出兩個對象的屬性位址,相同
  }
  return 0;
}      

結果:

0x1002036f0,0x100200330 //不同
0x1227,0x1227 //相同      

(2)深拷貝的案例。

按道理是隻需要把Person.m裡面的指派語句改成下面的樣子,就能實作深拷貝:

person.name=[_name copy]; 
person.age=[_age copy];      

但是,因為cocoa優化過了,是以有如下規則:

a:如果是Foundation架構裡的不可變對象,就是Array,NSString等建立的對象,直接用copy來拷貝相當于retain,也就是屬性還是同一個;

b:如果是用mutableCopy來拷貝,不管是可變還是不可變對象,屬性神馬的都直接拷貝了一份,即真正意義上得拷貝,它拷貝出來的對象統統都是可變的;

c:如果是可變對象,我們用copy也能實作真正意義上的拷貝,但是拷貝出來的對象是不可變的。

是以,我們拿name實驗(因為age沒有mutableCopy)實作語句的修改:

person.name=[_name mutableCopy]
person.age=[_age copy];      

然後再輸出person1和person2的name屬性的位址,發現就不同了。

總結:

淺拷貝和深拷貝在實際項目中不常用,可以做一般了解。

OC-深淺複制

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

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

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

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

              2、對于完全複制如何實作(目前通用的辦法是:疊代法和歸檔),這裡後續是否添加視情況而定,

              暫時不做講解。

          3、指針複制俗稱指針拷貝,對象複制也俗稱内容拷貝。

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

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

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

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

不可變對象:值發生改變,其記憶體首位址随之改變。

   可變對象:無論值是否改變,其記憶體首位址都不随之改變。

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

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

#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後為:::%lun",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

   //非容器類不可變對象

   //原始位址::::::::::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後引用計數為::::%lun",array1.retainCount);

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

        printf("nretain複制::::::::%pt%p",arrayCopy1,[arrayCopy1 objectAtIndex:1]);

        printf("ncopy複制::::::::::%pt%p",arrayCopy2,[arrayCopy2 objectAtIndex:1]);

        printf("nmutableCopy複制:::%pt%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後引用計數為::::%lun",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   = [NSMutableArrayarrayWithObjects:@"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後引用計數為::%lun",array2.retainCount);

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

       printf("nretain複制:::::::::%pt%p",arrayCpy1,[arrayCpy1 objectAtIndex:1]);

       printf("ncopy複制:::::::::::%pt%p",arrayCpy2,[arrayCpy2 objectAtIndex:1]);

       printf("nnmutableCopy複制:::%pt%p",arrayCpy3,[arrayCpy3 objectAtIndex:1]);

         //初始化指派引用計數為::::::::::1

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

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

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

         //容器類可變數組

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

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

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

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

    }