iOS - copy與mutableCopy

圖片源于網絡

淺拷貝與深拷貝

  • 淺拷貝:指針拷貝,不產生新的對象,源對象的引用計數器+1

  • 深拷貝:對象拷貝,會產生新的對象,源對象的引用計數器不變

    淺拷貝與深拷貝

copy與mutableCopy

  • copy:拷貝的結果是一個不可變(imutable)的對象, 無論源對象是可變的還是不可變的,copy之后的都是不可變的類型

    不可變類型 變量名 = [不可變類型 copy];

    不可變類型 變量名 = [可變類型 copy];

  • mutableCopy:可變拷貝的結果的數據類型是一個可變的對象,無論源對象時不可變的還是可變的,可變拷貝之后的數據類型都是可變類型

    可變類型 變量名 = [不可變類型 mutableCopy];

    可變類型 變量名 = [可變類型 mutableCopy];

  • copy對引用計數器的影響:

    • 拷貝一個不可變的類型的結果是新對象和源對象都指向同一個內存地址,即使指針拷貝,屬于淺拷貝,所以不生產新對象,源對象的引用計數+1

    • 拷貝一個可變的類型,會生成一個新對象,不影響源對象的引用計數

  • mutableCopy對引用計數器的影響:

    • 無論對可變類型或者對不可變類型使用mutableCopy操作,都不會影響源對象的引用計數

copy與mutableCopy的使用

    1. 系統(tǒng)非容器類對象
    • 不可變類型
    NSString *str = @"123";
    NSString *strCopy = [str copy];
    NSMutableString *mustr = [str copy];
    NSMutableString *mustrCopy = [str mutableCopy];
    //    [mustr appendString:@"4"];    //會崩潰
    [mustrCopy appendString:@"5"];
    NSLog(@"str = %@,str地址 = %p,strCopy = %@,strCopy地址 = %p ",str,str,strCopy,strCopy);
    NSLog(@"mustr = %@,mustr地址 = %p,mustrCopy = %@,mustrCopy地址 = %p",mustr ,mustr,mustrCopy,mustrCopy);
    
    /**
     str = 123,str地址 = 0x102ad4098,strCopy = 123,strCopy地址 = 0x102ad4098
     mustr = 123,mustr地址 = 0x102ad4098,mustrCopy = 1235,mustrCopy地址 = 0x1c444bca0
     */
    
    • 可變類型
    NSMutableString *mustr1 = [NSMutableString stringWithFormat:@"123"];
    NSString *immutableStrCopy = [mustr1 copy];
    NSMutableString *mutableStr = [mustr1 copy];
    NSMutableString *mutableStrCopy = [mustr1 mutableCopy];
    //    [mutableStr appendString:@"5"];    //會崩潰
    [mutableStrCopy appendString:@"6"];
    
    
    NSLog(@"mustr1 = %@,mustr1地址 = %p,immutableStrCopy = %@,immutableStrCopy地址 = %p ",mustr1,mustr1,immutableStrCopy,immutableStrCopy);
    NSLog(@"mutableStr = %@,mutableStr地址 = %p,mutableStrCopy = %@,mutableStrCopy地址 = %p",mutableStr ,mutableStr,mutableStrCopy,mutableStrCopy);
    
    /**
     mustr1 = 123,mustr1地址 = 0x1c0247c80,immutableStrCopy = 123,immutableStrCopy地址 = 0xa000000003332313
     mutableStr = 123,mutableStr地址 = 0xa000000003332313,mutableStrCopy = 1236,mutableStrCopy地址 = 0x1c0247c20
     */
    
    • 總結

    • 對系統(tǒng)非容器類不可變對象調用Copy方法其實只是把當前對象的指針指向了原對象的地址。

    • 調用mutableCopy方法則是新分配了一塊內存區(qū)域并把新對象的指針指向了這塊區(qū)域。

    • 對于可變對象來說調用Copy和MutableCopy方法都會重新分配一塊內存。

    • copy和mutableCopy的區(qū)別在于copy在復制對象的時候其實是返回了一個不可變對象,因此當調用方法改變對象的時候會崩潰。

    1. 系統(tǒng)容器類對象
    • 不可變類型

      NSArray *array = [NSArray arrayWithObjects:@"1",@"2",@"3", nil];
      NSArray *arrayCopy = [array copy];
      NSMutableArray *musarray = [array copy];
      NSMutableArray *musarrayCopy = [array mutableCopy];
      NSLog(@"array = %@,array地址 = %p,arrayCopy = %@,arrayCopy地址 = %p ",array,array,arrayCopy,arrayCopy);
      NSLog(@"musarray = %@,musarray地址 = %p,musarrayCopy = %@,musarrayCopy地址 = %p",musarray ,musarray,musarrayCopy,musarrayCopy);
      /**
       array = (
       1,
       2,
       3
       ),array地址 = 0x1c44508f0,
       arrayCopy = (
       1,
       2,
       3
       ),arrayCopy地址 = 0x1c44508f0
       musarray = (
       1,
       2,
       3
       ),musarray地址 = 0x1c44508f0,
       musarrayCopy = (
       1,
       2,
       3
       ),musarrayCopy地址 = 0x1c4653c20
       */
      
    • 可變類型

      NSMutableArray *muarray = [NSMutableArray arrayWithObjects:[NSMutableString stringWithString:@"1"],@"2",@"3", nil];
      NSArray *immutableArrayCopy = [muarray copy];
      NSArray *mutableArrayCopy = [muarray mutableCopy];
      NSMutableArray *mutArray = [muarray copy];
      NSMutableArray *mutArrayCopy = [muarray mutableCopy];
      
      NSLog(@"muarray = %@,muarray地址 = %p,immutableArrayCopy = %@,immutableArrayCopy地址 = %p,mutableArrayCopy = %@, mutableArrayCopy地址 =  %p",muarray,muarray,mutableArrayCopy,mutableArrayCopy,immutableArrayCopy,immutableArrayCopy);
      NSLog(@"mutArray = %@,mutArray地址 = %p,mutArrayCopy = %@,mutArrayCopy地址 = %p",mutArray ,mutArray,mutArrayCopy,mutArrayCopy);
      /**
      muarray = (
       1,
       2,
       3
       ),muarray地址 = 0x6040004434b0,
       immutableArrayCopy = (
       1,
       2,
       3
       ),immutableArrayCopy地址 = 0x604000443750,
       mutableArrayCopy = (
       1,
       2,
       3
       ), mutableArrayCopy地址 =  0x604000443540
       mutArray = (
       1,
       2,
       3
       ),mutArray地址 = 0x604000443ba0,
       mutArrayCopy = (
       1,
       2,
       3
       ),mutArrayCopy地址 = 0x604000443600
       */
      
      //對于可變對象不管調用Copy還是MutableCopy都是新分配一塊內存。但是雖然重新分配了一塊內存,但是對象里面的數據依然是指針復制的
      NSMutableString *mustr = muarray[0];
      [mustr appendString:@"2"];
      NSLog(@"muarray = %@,muarray地址 = %p,immutableArrayCopy = %@,immutableArrayCopy地址 = %p,mutableArrayCopy = %@, mutableArrayCopy地址 =  %p",muarray,muarray,mutableArrayCopy,mutableArrayCopy,immutableArrayCopy,immutableArrayCopy);
      NSLog(@"mutArray = %@,mutArray地址 = %p,mutArrayCopy = %@,mutArrayCopy地址 = %p",mutArray ,mutArray,mutArrayCopy,mutArrayCopy);
      /**
       muarray = (
       12,
       2,
       3
       ),muarray地址 = 0x6040004434b0,
       immutableArrayCopy = (
       12,
       2,
       3
       ),immutableArrayCopy地址 = 0x604000443750,
       mutableArrayCopy = (
       12,
       2,
       3
       ), mutableArrayCopy地址 =  0x604000443540
       mutArray = (
       12,
       2,
       3
       ),mutArray地址 = 0x604000443ba0,
       mutArrayCopy = (
       12,
       2,
       3
       ),mutArrayCopy地址 = 0x604000443600
       */
      //可以看到當更改原數組的值之后,所有新數組的值都更改了,即使調用了MutableCopy方法創(chuàng)建的新數組里面的值也因此更改,所以可以看出對于系統(tǒng)容器類對象,其元素對象始終是指針復制
      
    • 總結

      • 對系統(tǒng)容器類不可變對象調用Copy方法其實只是把當前對象的指針指向了原對象的地址。

      • 調用mutableCopy方法則是新分配了一塊內存區(qū)域并把新對象的指針指向了這塊區(qū)域。

      • 對于系統(tǒng)容器類可變對象來說調用Copy和MutableCopy方法都會重新分配一塊內存。

      • 對于系統(tǒng)容器類可變對象,雖然重新分配了一塊內存,但是對象里面的數據依然是指針復制的。

    1. 自定義對象
    • 在iOS中并不是所有對象都支持Copy和MutableCopy,遵循NSCopying協議的類可以發(fā)送Copy協議,遵循NSMutableCopying協議的類可以發(fā)送MutableCopy消息。

    • 如果一個對象沒有遵循這兩個協議而發(fā)送Copy或者MutableCopy消息那么會發(fā)生異常。

    • 如果要遵循NSCopying協議,那么必須實現copyWithZone方法。

    • 如果要遵循NSMutableCopying協議那么必須實現mutableCopyWithZone方法。

    • 對于自定義對象來說調用Copy和MutableCopy方法都會重新分配一塊內存。

//  Man.h
#import <Foundation/Foundation.h>

@interface Man : NSObject<NSCopying,NSMutableCopying>
@property (nonatomic,strong)NSString *name;
@property (nonatomic,assign)NSInteger year;
@end
//  Man.m
#import "Man.h"

@implementation Man
#pragma mark description方法內部不能打印self,不然會造成死循環(huán)
- (NSString *)description {
    return [NSString stringWithFormat:@"[name = %@,year = %ld]", _name,_year];
}
//自定義深拷貝,實現copyWithZone方法
-(id)copyWithZone:(NSZone *)zone{
    Man *newMan = [[[self class] allocWithZone:zone] init];
    newMan.name = self.name;
    newMan.year = self.year;
    return newMan;
}

-(id)mutableCopyWithZone:(NSZone *)zone{
    Man *newMan = [[[self class] allocWithZone:zone] init];
    newMan.name = self.name;
    newMan.year = self.year;
    return newMan;
}
@end
//調用
    Man *man = [[Man alloc]init];
    man.name = @"張三";
    man.year = 1;
    Man *newMan = [man copy];
    Man *newMutMan = [man mutableCopy];
    NSLog(@"man = %@,man地址 = %p,newMan = %@,newMan地址 = %p,newMutMan = %@, newMutMan地址 =  %p",man,man,newMan,newMan,newMutMan,newMutMan);
    /**
     man = [name = 張三,year = 1],
     man地址 = 0x604000036900,
     newMan = [name = 張三,year = 1],
     newMan地址 = 0x6040004207e0,
     newMutMan = [name = 張三,year = 1],
     newMutMan地址 =  0x60400003c2a0
     */
    newMan.name = @"李四";
    NSLog(@"man = %@,man地址 = %p,newMan = %@,newMan地址 = %p,newMutMan = %@, newMutMan地址 =  %p",man,man,newMan,newMan,newMutMan,newMutMan);
    /**
     man = [name = 張三,year = 1],
     man地址 = 0x604000036900,
     newMan = [name = 李四,year = 1],
     newMan地址 = 0x6040004207e0,
     newMutMan = [name = 張三,year = 1],
     newMutMan地址 =  0x60400003c2a0
     */
    newMutMan.name = @"王五";
    NSLog(@"man = %@,man地址 = %p,newMan = %@,newMan地址 = %p,newMutMan = %@, newMutMan地址 =  %p",man,man,newMan,newMan,newMutMan,newMutMan);
    /**
     man = [name = 張三,year = 1],
     man地址 = 0x604000036900,
     newMan = [name = 李四,year = 1],
     newMan地址 = 0x6040004207e0,
     newMutMan = [name = 王五,year = 1],
     newMutMan地址 =  0x60400003c2a0
     */
    1. 總結
    • 非集合類對象的 copy 操作:

      • [immutableObject copy] 淺復制
      • [immutableObject mutableCopy] 深復制
      • [mutableObject copy] 深復制
      • [mutableObject mutableCopy] 深復制
    • 集合類的對象進行 copy 操作:

      • [immutableObject copy] 淺復制(對象地址和被復制的對象地址一樣)
      • [immutableObject mutableCopy] 單層深復制
      • [mutableObject copy] 單層深復制
      • [mutableObject mutableCopy] 單層深復制
    • 自定義對象

      • 如果要遵循NSCopying協議,那么必須實現copyWithZone方法。

      • 如果要遵循NSMutableCopying協議那么必須實現mutableCopyWithZone方法。

      • [customObject copy] 深復制

      • [customObject mutableCopy] 深復制

block為什么要使用copy

  • block使用copy是在MRC中延續(xù)下來的,在MRC下,方法內部的block是存放在棧區(qū),使用copy會將block拷貝到堆區(qū)。

  • 在ARC下編譯器會自動對block進行copy,因此我們使用copy或者strong的效果是一樣的。但是我們在ARC下繼續(xù)使用copy可以提醒我們編譯器會自動幫我們實現copy的操作。

參考

iOS 淺拷貝和深拷貝的區(qū)別? copy和mutableCopy的區(qū)別?

iOS深拷貝(MutableCopy)與淺拷貝(Copy)的區(qū)別

ios深拷貝,淺拷貝,拷貝自定義對象的簡單介紹

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • 參考鏈接 一、深拷貝和淺拷貝#### 深拷貝:對象拷貝 - 直接拷貝內容。 單層深拷貝:這種方式只能夠提供一層內存...
    Mitchell閱讀 7,082評論 11 41
  • 本文為轉載: 作者:zyydeveloper 鏈接:http://www.itdecent.cn/p/5f776a...
    Buddha_like閱讀 1,012評論 0 2
  • 一、從面向對象到Objective-C概覽copy 1、面向對象: In object-oriented prog...
    adrian920閱讀 822評論 0 3
  • 1、對象拷貝有兩種方式:淺復制和深復制。顧名思義,淺復制,并不拷貝對象本身,僅僅是拷貝指向對象的指針;深復制是直接...
    滴答大閱讀 847評論 0 2
  • 查看之前項目的時候有個小功能記錄一下關于App分組展示的功能,記得當時是仿照360Launcher做的 效果如圖所...
    Andy周閱讀 870評論 0 0

友情鏈接更多精彩內容