Copy與mutableCopy的個人理解

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