Copy與mutableCopy的個人理解

Solist發表於2020-05-19

Copy與mutableCopy的個人理解

1. 相同點

  • 都是將原有物件進行深拷貝(狹義)

    這裡的狹義上的深拷貝指的是在不考慮編譯器在編譯時對不可變物件進行copy時採取的優化策略:即將不可變物件的地址直接賦值給拷貝物件,因為不可變物件無法進行修改,也就不存在拷貝後原值改變的情況,所以為了效率,即不再重新開闢空間,編譯器對不可變物件採取了淺拷貝的方式

    淺拷貝 :只是對指標的拷貝,拷貝後兩個指標指向同一個記憶體空間。

    深拷貝 :不但對指標進行拷貝,而且對指標指向的內容進行拷貝,經深拷貝後的指標是指向兩個不同地址的指標。

  • 都是為了防止因原物件改變而造成拷貝物件改變的策略

    不可變物件除外

2.不同點

  • 無論是可變物件還是不可變物件進行copy,返回值一律是不可變物件(與被拷貝物件無關)

    可變物件copy後自然會拷貝一個新的地址給不可變型別的拷貝物件(深拷貝),而不可變物件因為優化策略則為淺拷貝

    NSMutableString* mstr=[NSMutableString stringWithString:@"1"];
    NSString *str=[mstr copy]; //將物件copy給不可變物件
    [mstr appendFormat:@"2"];//因為深拷貝,str不會因mstr改變而改變
    NSLog(@"%@",str); //輸出1
    
    NSString* str0=@"1";
    NSMutableString *str1=[str0 copy];
    NSLog(@"%p:%p",str0,str1); //0x100001040:0x100001040  淺拷貝
    

    tips:當拷貝物件為可變物件時,使用copy會導致crash(在copy後使用append方法試圖改變拷貝物件時)

    NSMutableString* mstr0=[NSMutableString stringWithString:@"1"];
    NSMutableString *mstr1=[mstr0 copy]; //將物件copy給可變物件
    [mstr0 appendFormat:@"2"];//因為深拷貝,mstr1不會因mstr0改變而改變
    NSLog(@"%@",str); //輸出1
    [mstr1 appendFormat:@"2"];//crash,因為經過copy後mstr1已經變為了不可變物件(多型,NSMutableString是NSString的子類)
    
  • 無論是可變物件還是不可變物件進行mutableCopy,返回值一律是可變物件(與被拷貝物件無關,且狹義上深拷貝)

    狹義上的深拷貝指的是對於非容器類,而非容器類只是深拷貝容器,而容器內的物件則為指標拷貝(淺拷貝)

    容器類:NSArray、NSDictionary、NSSet

    如果要對容器類進行完全深拷貝,一般使用物件方法:-(id)initWithArray: copyItems:

    tips:當拷貝物件為不可變物件時,使用mutableCopy會將不可變物件改為可變物件

    NSString* str0=@"1";
    NSString *str1=[str0 mutableCopy]; //將物件mutableCopy給不可變物件
    [(NSMutableString *)str1 appendFormat:@"2"];//這裡的str已經為可變物件,但編譯器因為看不到可變物件的appendFormat方法,所以這裡需要強轉換為NSMutableString(若str這裡不是真正指向可變物件,則會報錯,但這裡未報錯,所以str已經指向了一個可變物件,即深拷貝)
    NSLog(@"%@",str1); //輸出12
    

3.總結

無論是copy還是mutableCopy都可以看作是為了讓被拷貝物件與拷貝物件進行分離,互不干擾的一種策略(通過深拷貝實現,雖然有兩個例外:編譯器優化(其實無影響)和容器類的假深拷貝)。只不過一個返回的是不可變物件,而另一個返回的是可變物件,僅此而已

相關文章