zoukankan      html  css  js  c++  java
  • 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;
          }
          
  • 相关阅读:
    怎么防止重复提交
    如何重新加载 Spring Boot 上的更改,而无需重新启动服务器?
    什么是 JavaConfig?
    Spring Boot 有哪些优点?
    GBK和GB2312编码
    2.补充:计算机表示的单位:
    python中字符串的编码和解码
    Spring Boot 有哪些优点?
    Maven的工程类型有哪些?
    Maven仓库是什么
  • 原文地址:https://www.cnblogs.com/theDesertIslandOutOfTheWorld/p/4802548.html
Copyright © 2011-2022 走看看