iOS-深拷贝和浅拷贝

article/2025/10/12 9:28:54

一、深拷贝(Deep Copy) 和 浅拷贝(Shallow Copy)

1、深拷贝(Deep Copy)内容拷贝,拷贝数据到一块新内存区域,指针指向拷贝的数据区

(另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象)

2、浅拷贝(Shallow Copy)指针拷贝,复制一个新的指针,指针指向同一块内存区域。实际内存并没有发生拷贝

(只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存)

1、对不可变对象执行copy操作,是浅拷贝(指针拷贝,内容相同),都指向同一片存储空间,源数据被修改,副本数据也会被修改
2、对不可变字符串执行mutCopy操作,是深拷贝(对象拷贝),两者指向不同的存储空间
3、可变字符串执行copy或mutCopy都是深拷贝
4、可变容器类执行copy或mutcopy或者不可变容器执行mutCopy都是不完全深拷贝,即只是容器对象指向不同的内存空间,内部的元素则指向同一个内存
5、可变数组执行copy(NSMutableArray执行copy后返回的NSArray),在使用过程回出现crash的问题
6、数组完全深拷贝需要执行initWithArray:copyItems: 方法
NSArray *deepCopy = [[NSArray alloc] initWithArray:array copyItems:YES];

参考苹果官方原图:苹果官网文档

深拷贝参考下图:

浅拷贝参考下图: 

在Objective-C中并不是所有的对象都支持Copy,MutableCopy,遵守NSCopying协议的类才可以发送Copy消息,遵守NSMutableCopying 协议的类才可以发送MutableCopy消息.

二、对非集合对象的copy和mutableCopy

以NSString类型举例:

    NSLog(@"--不可变NSString--");NSString *string = @"123";NSString *stringCopy = [string copy];NSLog(@"--不可变NSString--copy--");NSLog(@"string的地址:%p,stringCopy的地址:%p",string,stringCopy);NSMutableString *stringMCopy = [string mutableCopy];NSLog(@"--不可变NSString--mutableCopy--");NSLog(@"stringMCopy的地址:%p",stringMCopy);
//    string = @"123456";
//    NSLog(@"string:%@    stringCopy:%@    stringMCopy:%@",string,stringCopy,stringMCopy);NSLog(@"");NSLog(@"--可变NSMutableString--");NSMutableString * mString = [NSMutableString stringWithString:@"123"];NSString *mStringCopy = [mString copy];NSLog(@"--可变NSMutableString--copy--");NSLog(@"mString的地址:%p,mStringCopy的地址:%p",mString,mStringCopy);NSMutableString *mStringMCopy = [mString mutableCopy];NSLog(@"--可变NSMutableString--mutableCopy--");NSLog(@"mStringMCopy的地址:%p",mStringMCopy);

输出结果

通过查看内存,可以看到 stringCopy 和 string 的地址是一样,进行了指针拷贝;而 stringMCopy 的地址和 string 不一样,进行了内容拷贝;

可以看到 mStringCopy 和 mString 的地址是一样,进行了内容拷贝;而 mStringMCopy 的地址和 mString 不一样,进行了内容拷贝;

因此,得出结论:

非集合对象(immutableObject)的copy和mutableCopy

对immutable对象进行copy操作,是指针拷贝,mutableCopy操作时内容拷贝;对mutable对象进行copy和mutableCopy都是内容拷贝。

[immutableObject copy]  //浅拷贝
[immutableObject mutableCopy]  //深拷贝
[mutableObject copy]  //深拷贝
[mutableObject mutableCopy]  //深拷贝

三、对集合对象的copy和mutableCopy

集合对象指的是NSArray,NSDictionary,NSSet等类的对象。

    NSLog(@"--不可变NSArray--");NSArray *array = @[@1, @2, @3, @4];NSArray *arrayCopy = [array copy];NSMutableArray *arrayMCopy = [array mutableCopy];NSLog(@"--不可变NSArray--copy--");NSLog(@"array的地址:%p; arrayCopy的地址:%p; arrayMCopy的地址:%p",array,arrayCopy,arrayMCopy);NSLog(@"--不可变NSArray--mutableCopy--");NSLog(@"array的第一个元素地址:%p; arrayCopy的第一个元素地址:%p; arrayMCopy的第一个元素地址:%p",array[0],arrayCopy[0],arrayMCopy[0]);NSLog(@"");NSLog(@"--可变NSMutableArray--");NSMutableArray *mArray = [NSMutableArray arrayWithObjects:@1, @2, @3, @4, nil];NSArray *mArrayCopy = [mArray copy];NSMutableArray *mArrayMCopy = [mArray mutableCopy];NSLog(@"--可变NSMutableArray--copy--");NSLog(@"mArray的地址:%p; mArrayCopy的地址:%p; mArrayMCopy的地址:%p",mArray,mArrayCopy,mArrayMCopy);NSLog(@"--可变NSMutableArray--mutableCopy--");NSLog(@"mArray的第一个元素地址:%p; mArrayCopy的第一个元素地址:%p; mArrayMCopy的第一个元素地址:%p",mArray[0],mArrayCopy[0],mArrayMCopy[0]);

输出结果

查看内容,可以看到arrayCopy和array的地址是一样的,而arrayMCopy和array的地址是不同的。说明copy操作进行了指针拷贝,mutableCopy进行了内容拷贝。但需要强调的是:此处的内容拷贝,仅仅是拷贝array这个对象,array集合内部的元素仍然是指针拷贝。

mArrayCopy、mArrayMCopy和mArray的内存地址都不一样,说明mArrayCopy、mArrayMCopy都对mArray进行了内容拷贝,mArray集合内部的元素仍然是指针拷贝。

因此,在集合类对象中,对immutable对象进行copy,是指针拷贝,mutableCopy是内容拷贝;对mutable对象进行copy和mutableCopy都是内容拷贝。但是:集合对象的内容拷贝仅限于对象本身,对象元素仍然是指针拷贝。

[immutableObject copy]     // 浅拷贝
[immutableObject mutableCopy]   //单层深拷贝
[mutableObject copy]      //单层深拷贝
[mutableObject mutableCopy]   //单层深拷贝

四、集合单层深拷贝(one-level-deep copy)

我们在上面NSArray和NSMutableArray不管是进行copy也好,还是mutableCopy也好,其实对象元素都是浅拷贝(指针拷贝),这种情况是属于深拷贝,还是浅拷贝?苹果官网文档有这样原话描述:

Deep Copies
There are two ways to make deep copies of a collection. You can use the collection’s equivalent of initWithArray:copyItems: with YES as the second parameter. If you create a deep copy of a collection in this way, each object in the collection is sent a copyWithZone: message. If the objects in the collection have adopted the NSCopying protocol, the objects are deeply copied to the new collection, which is then the sole owner of the copied objects. If the objects do not adopt the NSCopying protocol, attempting to copy them in such a way results in a runtime error. However, copyWithZone: produces a shallow copy. This kind of copy is only capable of producing a one-level-deep copy. If you only need a one-level-deep copy, you can explicitly call for one as in Listing 2.Listing 2  Making a deep copyNSArray *deepCopyArray=[[NSArray alloc] initWithArray:someArray copyItems:YES];
This technique applies to the other collections as well. Use the collection’s equivalent of initWithArray:copyItems: with YES as the second parameter.If you need a true deep copy, such as when you have an array of arrays, you can archive and then unarchive the collection, provided the contents all conform to the NSCoding protocol. An example of this technique is shown in Listing 3.Listing 3  A true deep copyNSArray* trueDeepCopyArray = [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:oldArray]];

关于浅拷贝深拷贝单层深拷贝做了概念区分:

浅拷贝(shallow copy): 在浅拷贝操作时,对于被拷贝对象的每一层都是指针拷贝。
深拷贝(one-level-deep copy):在深拷贝操作时,对于被拷贝对象,至少有一层是深拷贝。
完全拷贝(real-deep copy):在完全拷贝操作时,对于被拷贝对象的每一层都是对象拷贝。

我们要想对数组中的对象也进行深拷贝,要做到如下:

首先创建Person.hPerson.m,需要实现<NSCopying>协议,不然汇报如下错误:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[Person copyWithZone:]: unrecognized selector sent to instance 0x6000015084c0'

//Person.h 文件
@interface Person : NSObject<NSCopying>@property (nonatomic, copy) NSString *name;@end//Person.m 文件
@implementation Person//实现copyWithZone方法
- (id)copyWithZone:(NSZone *)zone {Person *p = [[self class] allocWithZone:zone];p.name = [self name];return p;
}@end

实现如下:

    /*--------数组元素拷贝-------*/NSLog(@"");NSLog(@"--不可变NSArray--元素拷贝--");Person *person = [[Person alloc] init];[person setName:@"one"];NSArray *array1 = [[NSArray alloc] initWithObjects:person, nil];//注意仅仅是这里更改为了[[NSArray alloc] initWithArray:array1 copyItems:YES];NSArray *array2 = [[NSArray alloc] initWithArray:array1 copyItems:YES];Person *p = array2[0];[p setName:@"two"];//尝试更改name的值//获取两个数组里的各自Person对象Person *p1 = [array1 objectAtIndex:0];Person *p2 = [array2 objectAtIndex:0];NSLog(@"array1:%p",array1);NSLog(@"array2:%p",array2);NSLog(@"p1:%p",p1);NSLog(@"p2:%p",p2);NSLog(@"p1.name:%@",p1.name);NSLog(@"p2.name:%@",p2.name);NSLog(@"");NSLog(@"--可变NSMutableArray--元素拷贝--");Person *per = [[Person alloc] init];[per setName:@"one11"];NSMutableArray *array111 = [[NSMutableArray alloc] initWithObjects:person, nil];//注意仅仅是这里更改为了[[NSArray alloc] initWithArray:array1 copyItems:YES];NSMutableArray *array222 = [[NSMutableArray alloc] initWithArray:array111 copyItems:YES];Person *pp = array222[0];[pp setName:@"two22"];//尝试更改name的值//获取两个数组里的各自Person对象Person *p11 = [array111 objectAtIndex:0];Person *p22 = [array222 objectAtIndex:0];NSLog(@"array111:%p",array111);NSLog(@"array222:%p",array222);NSLog(@"p11:%p",p11);NSLog(@"p22:%p",p22);NSLog(@"p11.name:%@",p11.name);NSLog(@"p22.name:%@",p22.name);

输出结果:

我们可以看出,不但array1array2的内存地址发生改变,连array2里面的Person对象也发生改变,生成了另外一个Person对象,即使属于array1Person对象的元素name发生改变也不会影响到array2里的Person对象。

参考文章

浅拷贝(Shallow Copy)与深拷贝(Deep Copy) - 简书


http://chatgpt.dhexx.cn/article/uKveGgCe.shtml

相关文章

实现浅拷贝

浅拷贝是指&#xff0c;一个新的对象对原始对象的属性值进行精确地拷贝&#xff0c;如果拷贝的是基本数据类型&#xff0c;拷贝的就是基本数据类型的值&#xff0c;如果是引用数据类型&#xff0c;拷贝的就是内存地址。如果其中一个对象的引用内存地址发生改变&#xff0c;另一…

浅拷贝

图片转自js 深拷贝 vs 浅拷贝 我们平常说的深拷贝和浅拷贝都是基于对诸如 Object 和 Array 等引用数据类型的拷贝。对于基本数据而言&#xff0c;拷贝为某个值的赋值。 在说拷贝之前&#xff0c;我们先复习一下什么是基本数据类型和引用类型。 基本数据类型 JavaScript 中基…

深浅拷贝以及解决浅拷贝(以string浅拷贝为例)

一、什么是浅拷贝 在类和对象的时候&#xff0c;其中编译器生成的默认拷贝构造函数中&#xff0c;内置类型是按照字节方式直接拷贝的&#xff0c;而自定义类型是调用其拷贝构造函数完成拷贝的。 默认的拷贝构造函数对象按内存存储按字节序完成拷贝&#xff0c;这种拷贝叫做浅…

ctf之培根密码

根据特征怀疑是培根密码 flag{AAAABAAAAAAAABAABBBAABBABABAAABAABAAAABBAABAAABABBABAAAAAABAABAAAABBBABABAABAABA} 直接在线解密 https://tool.bugku.com/peigen/ flag{BACONISDELICIOUS}

培根密码加解密

分享一下我老师大神的人工智能教程&#xff01;零基础&#xff0c;通俗易懂&#xff01;http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章。分享知识&#xff0c;造福人民&#xff0c;实现我们中华民族伟大复兴&#xff01; 0x00 介绍 培根密码实际上就是一种替换密…

培根密码解密脚本

官方吐槽&#xff1a;疫情复发难受&#xff0c;什么时候是个头 #!/usr/bin/env python3 # -*- coding:utf-8 -*- #Author&#xff1a;later_future import string miweninput("请输入密文&#xff1a;") count0 msg"" flag"" #培根加密百度百科…

攻防世界crypto部分sherlock的writeup,原来不是培根密码。

下载附件后&#xff0c;发现是一个很大的文本&#xff0c;搜了下flag没啥收获。 1、后来看到下面这个 2、明显的故意大写&#xff0c;难道是培根密码&#xff1f;这就有思路了&#xff0c;将大写过滤出来&#xff1a; cat f590c0f99c014b01a5ab8b611b46c57c.txt | grep -Eo […

培根密码加解密(Python)

原理 加密时&#xff0c;明文中的每个字母会根据下面转换成5个字母&#xff1b; 解密时&#xff0c;密文中的每5个字母为一组转换成对应的1个字母&#xff1b; Python代码如下&#xff1a; CODE_TABLE { #培根字典aaaaa:a,aaaab:b,aaaba:c,aaabb:d,aabaa:e,aabab:f,aabba:…

CTF密码学-加解密总结

零基础学黑客&#xff0c;搜索公众号&#xff1a;白帽子左一密码学基本简介 密码学&#xff08;在西欧语文中&#xff0c;源于希腊语krypts“隐藏的”&#xff0c;和grphein“书写”&#xff09;是研究如何隐密地传递信息的学科。 在现代特别指对信息以及其传输的数学性研究&…

密码及编码

1. 密码 古典密码学 凯撒密码(Caeser)&#xff1a;位移密码 特殊形式&#xff08;加解密相同&#xff0c;因为26个字母是循环的&#xff09;&#xff1a;ROT13 栅栏密码&#xff1a;分组密码。 弗吉尼亚 现代密码学 对称加密算法&#xff1a;使用加密用过的秘钥及相同算法的…

CTF-密码学-培根密码

题目&#xff1a;bacon bAcon iS a MEaT prodUcT prePared frOm a pig and UsuALLy cUReD. 读题&#xff1a;翻译过来意思是培根 审题&#xff1a;联想到培根密码 解题&#xff1a;培根密码就是大写变A小写变B import string timu"bAcon iS a MEaT prodUcT prePared frOm…

【无标题】简单的培根密码解密

第一题 题目AABBBAABAAABABAABABAABBAB BABAAABBABBAAAAAAABB 此题由大写字母AB组成&#xff0c;不难看出这可以用培根密码转换器进行解密得出flag 解密得出flag&#xff5b;HELLO WORD&#xff5d;

CTF-Show密码学【摩斯码、培根密码】

萌新 密码33 一、题目信息 题目名称&#xff1a;我想吃培根题目描述&#xff1a;-- — .-. … . …–.- … … …–.- -.-. — — .-… …–.- -… …- - …–.- -… .- -.-. — -. …–.- … … …–.- -.-. — — .-… . .-. …–.- – – -… -… – -… – -… – – – -…

CTF-培根密码

CTF学习上的一些疑点和解疑 主题&#xff1a;培根密码的随意性 反正我是觉得挺离谱的 序章 CTF学习上的一些疑点和解疑前言&#xff1a;培根小贴士一、培根密码是什么&#xff1f;二、解答1.题目2.解密顺序 总结还没听懂的我给大家展现一些例子&#xff1a; 前言&#xff1a;…

密码学笔记——培根密码

培根密码,培根所用的密码是一种本质上用二进制数设计的,没有用通常的0和1来表示,而是采用a和b 一、培根密码加密方式 第一种方式: A aaaaa B aaaab C aaaba D aaabb E aabaa F aabab G aabba H aabbb I abaaa J abaab K ababa L ababb M abbaa N abbab O abbba P abb…

培根密码(Bacon)——python解密

简介 培根密码&#xff0c;又名倍康尼密码&#xff08;英语&#xff1a;Bacon’s cipher&#xff09;是由法兰西斯培根发明的一种隐写术。 特点&#xff1a; 培根密码本质上是将二进制信息通过样式的区别&#xff0c;加在了正常书写之上。培根密码所包含的信息可以和用于承载…

CTF-bacon(培根密码)

一、题目 培根密码实际上就是一种替换密码&#xff0c;根据所给表一一对应转换即可加密解密 。它的特殊之处在于&#xff1a;可以通过不明显的特征来隐藏密码信息&#xff0c;比如大小写、正斜体等&#xff0c;只要两个不同的属性&#xff0c;密码即可隐藏。 二、解题思路 …

【密码学 | CTF】培根密码

原理简述 加密方式有两种&#xff0c;但说实话我没看懂第二种的&#xff1b;i-j和u-v是怎么加密的呢&#xff1f;一解密岂不是乱了&#xff1f; 但解密用第一种方式就行了&#xff0c;每五个切割&#xff0c;对照字典解密即可&#xff0c;难度很小 def 培根密码_解密():培根密…

XML文档操作

文章目录 [toc] XML概述代码示例 CSS格式化XML为什么要用CSS样式表&#xff1a; 代码示例&#xff1a;代码详解&#xff1a; XSLT转化XMLXSLT简介&#xff1a;代码示例代码详解&#xff1a;正确的样式表声明从XML里提取数据节点匹配 DOM解析XMLXML DOM简介节点 代码示例代码详解…

XML文件的DOCTYPE定义

2019独角兽企业重金招聘Python工程师标准>>> DOCTYPE的常用声明&#xff1a;按照 HTML 4.01 XHTML 1.0 XHTML 1.1 列表如下&#xff0c;错误的DOCTYPE HTML PUBLIC反而会导致页面解析错误。HTML 4.01规范分为&#xff1a;Strict, Transitional, Frameset <!DO…