OC語言-08-深拷貝與淺拷貝詳解(示例)


概述


  • 拷貝:復制一個與源對象內容相同的對象
  • 實現拷貝,需要遵守以下兩個協議
    • NSCopying
    • NSMutableCopying
  • 拷貝返回對象的種類
    • 可變,mutableCopy消息返回的對象
    • 不可變,copy消息返回的對象
  • 拷貝的種類
    • 淺拷貝,只是復制了一個指向源對象的指針,未創建對象,未分配內存
    • 深拷貝,復制了源對象,創建了新對象,分配了內存
  • 注意
    • 系統對容器類的對象與非容器類的對象的內存處理是不同的,即當一個沒有被其他對象強引用的對象從容器中移除后,該對象就銷毀

Copy與Retain


  • copy
    • 是創建一個新的對象,內容拷貝
    • copy表示的是兩個對象的內容相同, 新對象的引用計數為1
    • 與舊對象的引用計數無關,就對象沒有變化
    • copy減少了對象對上下文的
  • retain
    • 創建的是一個指針,指針拷貝
    • 對象地址相同,內容固然相同
    • 對象的引用計數+1

不同對象的拷貝行為


  • 非容器對象(如NSString))

    • 對於不可變對象
      • 規則

        • copy,淺拷貝(指針復制)
        • mutableCopy,深拷貝(對象復制),返回對象可變(產生新的 可變對象)
      • 示例

        - (void)imutableInstanceCopy
        {
            NSString *string = @"Welcome to Xcode";
            
            //copy,淺拷貝
            NSString *stringCopy = [string copy];
            //mutableCopy,返回的對象可變
            NSMutableString *stringMutableCopy = [string mutableCopy];
            [stringMutableCopy appendString:@"!"];
            
            //string與stringCopy的內存地址相同
            NSLog(@"string: %p", string);
            NSLog(@"strongCopy: %p", stringCopy);
            
            //string與stringMutableCopy的內存地址不同,分配了新的內存
            NSLog(@"stringMCopy:%p", stringMutableCopy);
        }
        
    • 對於可變對象
      • 規則

        • copy,深拷貝(對象復制),返回對象不可變
        • mutableCopy,深拷貝(對象復制)
      • 示例

        - (void)mutableInstanceCopy
        {
            NSMutableString *mutableString = [NSMutableString stringWithString: @"Welcome to Xcode"];
            
            //深拷貝,返回對象不可變
            NSString *stringCopy = [mutableString copy];
            NSMutableString *mutableStringCopy = [mutableString copy];
            //運行時,此句會報錯,錯誤信息“Attempt to mutate immutable object with appendString:”
            [mutableStringCopy appendString:@"~~~"];
            
            //深拷貝,返回對象可變
            NSMutableString *stringMutableCopy = [mutableString mutableCopy];
            [stringMutableCopy appendString:@"!"];
            
            //三者與mutableString的內存地址都不同
            NSLog(@"mutableString: %p", mutableString);
            NSLog(@"string: %p", stringCopy);
            NSLog(@"mutableStringCopy: %p", mutableStringCopy);
            NSLog(@"stringMutbleCopy:%p", stringMutableCopy);
        }
        
  • 容器對象(NSArray

    • 遵循非容器對象的拷貝原則

    • 注意

      • 容器內的元素是指針賦值(淺拷貝)

      • 示例

        - (void)containerInstanceShallowCopy
        {
            NSArray *array = [NSArray arrayWithObjects:[NSMutableString stringWithString:@"Welcome"],@"to",@"Xcode",nil];
            
            //淺拷貝
            NSArray *arrayCopy = [array copy];
            //深拷貝
            NSMutableArray *arrayMutableCopy = [array mutableCopy];
            
            NSLog(@"array: %p", array);
            NSLog(@"arrayCopy: %p", arrayCopy);
            NSLog(@"arrayMutableCopy: %p", arrayMutableCopy);
            
            //容器內的對象是淺拷貝,即它們在內存中只有一份
            NSMutableString *testString = [array objectAtIndex:0];
            [testString appendString:@" you"];
            
            //三個數組的內容同時改變
            NSLog(@"array[0]: %@", array[0]);
            NSLog(@"arrayCopy[0]: %@", arrayCopy[0]);
            NSLog(@"arrayMutableCopy[0]: %@", arrayMutableCopy[0]);
        }
        
    • 實現真正意義上的深復制

      - (void)containerInstanceDeepCopy
      {
          NSArray *array = [NSArray arrayWithObjects:[NSMutableString stringWithString:@"Welcome"],@"to",@"Xcode",nil];
          
          //數組內對象是指針復制
          NSArray *deepCopyArray = [[NSArray alloc] initWithArray:array];
          //真正以上的深復制,數組內對象是對象復制
          NSArray *trueDeepCopyArray = [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:array]];
          
          NSLog(@"array: %p", array);
          NSLog(@"deepCopyArray: %p", deepCopyArray);
          NSLog(@"trueDeepCopyArray: %p", trueDeepCopyArray);
          
          //改變array的第一個元素
          [[array objectAtIndex:0] appendString:@" you"];
          
          //只影響deepCopyArray數組的第一個元素
          NSLog(@"array[0]: %@", array[0]);
          NSLog(@"arrayCopy[0]: %@", deepCopyArray[0]);
          //不影響trueDeepCopyArray數組的第一個元素,是真正意義上的深拷貝
          NSLog(@"arrayMutableCopy[0]: %@", trueDeepCopyArray[0]);
      }
      
  • 自定義對象

    • 在定義對象要實現拷貝,需要遵守NSCoping與NSMutableCoping協議,並實現以下方法
      • - (id)copyWithZone:(NSZone *)zone,可變拷貝
      • - (id)mutableCopyWithZone:(NSZone *)zone,不可變拷貝
    • 示例(自定對象Person的拷貝)
      • 遵守協議,設置成員屬性

        @interface Person : NSObject <NSCopying, NSMutableCopying>
        /**姓名*/
        @property (nonatomic, copy) NSMutableString *name;
        /**地址*/
        @property (nonatomic, copy) NSString *address;
        /**年齡*/
        @property (nonatomic, assign) NSInteger age;
        @end
        
      • 重寫初始化方法

        - (instancetype)init
        {
            if (self = [super init])
            {
                self.name = [[NSMutableString alloc] initWithString:@"XiaoYaowang"];
                self.address = @"世俗孤島";
                self.age = 3;
            }
            return self;
        }
        
      • 實現- (id)copyWithZone:(NSZone *)zone

        - (id)copyWithZone:(NSZone *)zone
        {
            Person *p = [[[self class] allocWithZone:zone] init];
            p.name = [self.name copy];
            p.address = [self.address copy];
            p.age =  self.age;
            
            return p;
        }
        
      • 實現- (id)mutableCopyWithZone:(NSZone *)zone

        - (id)mutableCopyWithZone:(NSZone *)zone
        {
            Person *p = [[[self class] allocWithZone:zone] init];
            //注意,此處是mutableCopy方法
            p.name = [self.name mutableCopy];
            p.address = [self.address copy];
            p.age =  self.age;
            
            return p;
        }
        


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM