OC细节 - 1.深拷贝与浅拷贝详解

概述


  • 拷贝:复制一个与源对象内容相同的对象
  • 实现拷贝,需要遵守以下两个协议
    • 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;
        }

---恢复内容结束---

时间: 2024-10-12 22:53:12

OC细节 - 1.深拷贝与浅拷贝详解的相关文章

【转】 c++拷贝构造函数(深拷贝,浅拷贝)详解

c++拷贝构造函数(深拷贝,浅拷贝)详解 2013-11-05 20:30:29 分类: C/C++ 原文地址:http://blog.chinaunix.net/uid-28977986-id-3977861.html 一.什么是拷贝构造函数      首先对于普通类型的对象来说,它们之间的复制是很简单的,例如: int a=100; int b=a; 而类对象与普通对象不同,类对象内部结构一般较为复杂,存在各种成员变量.  下面看一个类对象拷贝的简单例子. #include<iostream

IOS中复制对象的用法及深拷贝和浅拷贝详解

亲爱的网友,我这里有套课程想和大家分享,如果对这个课程有兴趣的,可以加我的QQ2059055336和我联系. 课程内容简介 我们软件是基于移动设备的.所以我们必然的选择了安卓作为我们的开发工具.课程中,我们将简要的介绍Android的基本概念,然后进行我们的实战开发.在开发中,大家讲学习到基本的组件,适配UI,数据的存储,多线程下载,开机广播,闹钟提醒,短信发送等实际项目开发中碰到的有用的知识点.通过课程学习,让大家能够掌握Android软件开发的流程,注意点,及优化.帮助大家迅速的掌握Andr

**Python中的深拷贝和浅拷贝详解

Python中的深拷贝和浅拷贝详解 这篇文章主要介绍了Python中的深拷贝和浅拷贝详解,本文讲解了变量-对象-引用.可变对象-不可变对象.拷贝等内容. 要说清楚Python中的深浅拷贝,需要搞清楚下面一系列概念: 变量-引用-对象(可变对象,不可变对象)-切片-拷贝(浅拷贝,深拷贝) [变量-对象-引用] 在Python中一切都是对象,比如说:3, 3.14, 'Hello', [1,2,3,4],{'a':1}...... 甚至连type其本身都是对象,type对象 Python中变量与C/

javascript实现引用数据类型的深拷贝和浅拷贝详解

关于引用类型值的详解,请看另一篇随笔 https://www.cnblogs.com/jinbang/p/10346584.html 深拷贝和浅拷贝,也就是引用数据类型栈和堆的知识点.深浅拷贝的原型都是Object,深拷贝指向的栈内存不一样,浅拷贝指向的栈内存一样): 如何区分深拷贝与浅拷贝,就是假设B复制了A,当修改A时,看B是否会发生变化,如果B没有发生变化,说明是深拷贝.如果B也跟着发生了变化,说明是浅拷贝. let obj = { name: "jin", arr: [&quo

c++拷贝构造函数(深拷贝,浅拷贝)详解

一.什么是拷贝构造函数      首先对于普通类型的对象来说,它们之间的复制是很简单的,例如: int a=100; int b=a; 而类对象与普通对象不同,类对象内部结构一般较为复杂,存在各种成员变量.  下面看一个类对象拷贝的简单例子. #include<iostream> using namespace std; class CExample { private: int a; public: //构造函数 CExample(int b) { a=b; printf("con

Javascript学习之深拷贝和浅拷贝详解

在JavaScript 中,存在着这样的两种拷贝方式.分别是:深拷贝和浅拷贝,这两种拷贝在实际中非常的常见,如果读者是一个阅读源码的爱好者,相信多多少少对深拷贝和浅拷贝有所了解.本文和大家分享的就是深拷贝和浅拷贝相关内容,一起来看看吧,希望对大家 学习javascript有所帮助. 一.浅拷贝 浅拷贝在现实中最常见的表现在赋值上面,例如 <!DOCTYPE html> <html lang="en"> <head> <meta charset=

iOS开发——深拷贝与浅拷贝详解

深拷贝和浅拷贝这个问题在面试中常常被问到,而在实际开发中,只要稍有不慎,就会在这里出现问题.尤其对于初学者来说,我们有必要来好好研究下这个概念.我会以实际代码来演示,相关示例代码上传至 这里 . 首先通过一句话来解释:深拷贝就是内容拷贝,浅拷贝就是指针拷贝. 深拷贝就是拷贝出和原来仅仅是值一样,但是内存地址完全不一样的新的对象,创建后和原对象没有任何关系.浅拷贝就是拷贝指向原来对象的指针,使原对象的引用计数+1,可以理解为创建了一个指向原对象的新指针而已,并没有创建一个全新的对象. (1)非容器

Python学习教程:Python列表赋值,复制,深拷贝及5种浅拷贝详解

Python学习教程:Python列表赋值,复制,深拷贝及5种浅拷贝详解 概述 在列表复制这个问题,看似简单的复制却有着许多的学问,尤其是对新手来说,理所当然的事情却并不如意,比如列表的赋值.复制.浅拷贝.深拷贝等绕口的名词到底有什么区别和作用呢? 列表赋值 # 定义一个新列表l1 = [1, 2, 3, 4, 5]# 对l2赋值l2 = l1print(l1)l2[0] = 100print(l1) 示例结果: [1, 2, 3, 4, 5][100, 2, 3, 4, 5] 可以看到,更改赋

oc中字典的实现方法详解

一:字典的基本概念 Foundation中的字典(NSDictionary,NSMutableDictionary)是由键-值对组成的数据集合.正如,我们在字典里查找单词的定义一样. 通过key(键),查找的对应的value(值),key通常是字符串对象,也可以是其他任意类型对象.在一个字典对象中,key的值必须是唯一的. 此外,字典对象的键和值不可以为空(nil),如果需要在字典中加入一个空值,可以加入NSNull对象 二:不可变字典-NSDictionary 1:初始化(以一个元素和多个元素