iOS - OC Copy 拷贝

前言

  • copy:需要先实现 NSCopying 协议,创建的是不可变副本。

  • mutableCopy:需要实现 NSMutableCopying 协议,创建的是可变副本。

  • 浅拷贝:指针拷贝,源对象和副本指向的是同一个对象。对象的引用计数器 +1,其实相当于做了一次 retain 操作。

  • 深拷贝:内容拷贝,源对象和副本指向的是两个不同的对象。源对象引用计数器不变,副本计数器设置为 1。

  • 只有不可变对象创建不可变副本(copy)才是浅拷贝,其它都是深拷贝。

  • 在 iOS 中并不是所有的对象都支持 copy,mutableCopy,遵守 NSCopying 协议的类可以发送 copy 消息,遵守 NSMutableCopying 协议的类才可以发送 mutableCopy 消息。假如发送了一个没有遵守上 诉两协议而发送 copy 或者 mutableCopy,那么就会发生异常。但是默认的 iOS 类并没有遵守这两个协议。如果想自定义一下 copy 那么就必须遵守 NSCopying,并且实现 copyWithZone: 方法,如果想自定义一下 mutableCopy 那么就必须遵守 NSMutableCopying,并且实现 mutableCopyWithZone: 方法。

  • copy 是创建一个新对象,retain 是创建一个指针,引用对象计数加 1。copy 属性表示两个对象内容相同,新的对象 retain 为 1 ,与旧有对象的引用计数无关,旧有对象没有变化。copy 减少对象对上下文的依赖。retain 属性表示两个对象地址相同(建立一个指针,指针拷贝),内容当然相同,这个对象的 retain 值 +1 也就是说,retain 是指针拷贝,copy 是内容拷贝。

1、系统的非容器类对象

    /*系统的非容器类对象指的是 NSString,NSNumber 等等一类的对象。对于系统的非容器类对象,如果对一不可变对象复制,copy 是指针复制(浅拷贝),mutableCopy 就是对象复制(深拷贝)。如果是对可变对象复制,都是深拷贝,但是 copy 返回的对象是不可变的。*/NSString *string = @"origion";NSString *stringCopy = [string copy];NSMutableString *mstringMCopy = [string mutableCopy];NSLog(@"%p", string);NSLog(@"%p", stringCopy);                       // 地址与 string 相同NSLog(@"%p", mstringMCopy);                     // 地址与 string 不同NSLog(@"%zi", [string retainCount]);            // 引用计数为 2NSLog(@"%zi", [stringCopy retainCount]);        // 引用计数为 2NSLog(@"%zi", [mstringMCopy retainCount]);      // 引用计数为 1NSLog(@"%@", stringCopy);                       // 内容与 string 相同NSLog(@"%@", mstringMCopy);                     // 内容与 string 相同[mstringMCopy appendString:@"!!"];              // mstringMCopy 是可变的NSLog(@"%@", mstringMCopy);/*string 和 stringCopy 指向的是同一块内存区域(又叫 apple 弱引用 weak reference),此时 stringCopy 的引用计数和 string 的一样都为2。而 mstringMCopy 则是我们所说的真正意义上的复制,系统为其分配了新内存,但指针所指向的字符串还是和 string 所指的一样。*/NSMutableString *mstring = [NSMutableString stringWithString: @"origion"];NSString *stringCopy = [mstring copy];NSMutableString *mStringCopy = [mstring copy];NSMutableString *mstringMCopy = [mstring mutableCopy];NSLog(@"%p", mstring);NSLog(@"%p", stringCopy);                       // 地址与 string 不同NSLog(@"%p", mStringCopy);                      // 地址与 string 不同,与 stringCopy 相同NSLog(@"%p", mstringMCopy);                     // 地址与 string 不同NSLog(@"%@", mstring);NSLog(@"%@", stringCopy);                       // 内容与 string 相同NSLog(@"%@", mStringCopy);                      // 内容与 string 相同NSLog(@"%@", mstringMCopy);                     // 内容与 string 相同[mstring appendString:@" origion!"];// [mStringCopy appendString:@"mm"];            // error,mStringCopy 不可变[mstringMCopy appendString:@"!!"];              // mstringMCopy 可变NSLog(@"%@", mstring);NSLog(@"%@", mstringMCopy);/* 以上四个 NSString 对象所分配的内存都是不一样的。但是对于 mStringCopy 其实是个不可变对象,所以上述会报错。*/

2、系统的容器类对象

    /*系统的容器类对象指 NSArray,NSDictionary 等。对于容器类本身,上面讨论的结论也是适用的,需要探讨的是复制后容器内对象的变化。对于系统的容器类对象,copy 返回不可变对象,是指针复制,包括里面的元素也是指向相同的指针。mutablecopy 返回可变对象,是对象复制,其中容器内的元素内容都是指针复制,可以改变其内的元素。*/NSArray *array = [NSArray arrayWithObjects:@"a", @"b", @"c", nil];NSArray *arrayCopy = [array copy];NSMutableArray *mArrayMCopy = [array mutableCopy];NSLog(@"%p", array);NSLog(@"%p", arrayCopy);                        // 地址与 array 相同NSLog(@"%p", mArrayMCopy);                      // 地址与 array 不同NSLog(@"%zi",[array retainCount]);NSLog(@"%zi",[arrayCopy retainCount]);NSLog(@"%zi",[mArrayMCopy retainCount]);NSLog(@"%@", array);NSLog(@"%@", arrayCopy);                        // 内容与 array 相同NSLog(@"%@", mArrayMCopy);                      // 内容与 array 相同[mArrayMCopy addObject:@"de"];                  // mArrayMCopy 可变NSLog(@"%@", array);NSLog(@"%@", mArrayMCopy);[mArrayMCopy removeObjectAtIndex:0];NSLog(@"%@", array);NSLog(@"%@", mArrayMCopy);/*copy 返回不可变对象,mutablecopy 返回可变对象,arrayCopy 是指针复制,而 mArrayMCopy 是对象复制。arrayCopy 是和 array 同一个 NSArray 对象(指向相同的对象),包括 array 里面的元素也是指向相同的指针。mArrayMCopy 是 array 的可变副本,指向的对象和 array 不同,但是其中的元素和 array 中的元素指向的是同一个对象。mArrayMCopy 还可以改变其内的元素:删除或添加。但是注意的是,容器内的元素内容都是指针复制。*/NSArray *array = [NSArray arrayWithObjects:[NSMutableString stringWithString:@"a"], @"b", @"c", nil];NSArray *arrayCopy = [array copy];NSMutableArray *mArrayMCopy = [array mutableCopy];NSLog(@"%p", array);NSLog(@"%p", arrayCopy);                        // 地址与 array 相同NSLog(@"%p", mArrayMCopy);                      // 地址与 array 不同NSLog(@"%zi",[array retainCount]);NSLog(@"%zi",[arrayCopy retainCount]);NSLog(@"%zi",[mArrayMCopy retainCount]);NSLog(@"%@", array);NSLog(@"%@", arrayCopy);                        // 内容与 array 相同NSLog(@"%@", mArrayMCopy);                      // 内容与 array 相同NSMutableString *testString = [array objectAtIndex:0];[testString setString:@"1a1"];                  // 这样会改变 testString 的指针,其实是将 @“1a1” 临时对象赋给了 testString。这样以上三个数组的首元素都被改变了。NSLog(@"%@", array);NSLog(@"%@", arrayCopy);                        // 内容与 array 相同NSLog(@"%@", mArrayMCopy);                      // 内容与 array 相同/*arrayCopy,mArrayMCopy 和 array 指向的都是不一样的对象,但是其中的元素都是一样的对象,同一个指针。对于容器而言,其元素对象始终是指针复制。如果需要元素对象也是对象复制,就需要实现深拷贝。*/NSArray *array = [NSArray arrayWithObjects:[NSMutableString stringWithString:@"first"], @"b", @"c", nil];NSArray *deepCopyArray = [[NSArray alloc] initWithArray:array copyItems: YES];// 使用归档/反归档拷贝NSArray *trueDeepCopyArray = [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject: array]];   NSLog(@"%@", array);NSLog(@"%@", deepCopyArray);                    // 内容与 array 相同NSLog(@"%@", trueDeepCopyArray);                // 内容与 array 相同NSMutableString *testString1 = [array objectAtIndex:0];[testString1 setString:@"1a1"];NSLog(@"%@", array);NSLog(@"%@", deepCopyArray);                    // 内容与 array 不同NSLog(@"%@", trueDeepCopyArray);                // 内容与 array 不同/*trueDeepCopyArray 是完全意义上的深拷贝,而 deepCopyArray 则不是,对于 deepCopyArray 内的不可变元素其还是指针复制。或者我们自己实现深拷贝的方法。因为如果容器的某一元素是不可变的,那你复制完后该对象仍旧是不能改变的,因此只需要指针复制即可。除非你对容器内的元素重新赋值,否则指针复制即已足够。举个例子,[[array objectAtIndex:0] appendstring:@”sd”] 后其他的容器内对象并不会受影响。[[array objectAtIndex:1] 和 [[deepCopyArray objectAtIndex:1] 尽管是指向同一块内存,但是我们没有办法对其进行修改——因为它是不可改变的。所以指针复制已经足够。所以这并不是完全意义上的深拷贝,但是 apple 的官方文档将其列为 deep copy 了,并添加了 copy 和 mutablity 的关系说明。*/

3、自定义对象

  • 需要自己要实现 NSCopying,NSMutableCopying 这样就能调用 copy 和 mutablecopy 了。
    // Teacher.h// 遵守 NSCopying, NSMutableCopying 协议@interface Teacher : NSObject <NSCopying, NSMutableCopying>@property (nonatomic, copy) NSString *name;@property (nonatomic, assign) int age;@end// Teacher.m@implementation Teacher// 实现协议方法,委托方会自动调用协议中的该方法- (id)copyWithZone:(NSZone *)zone{Teacher *copy = [[Teacher allocWithZone:zone] init];copy.name = self.name;copy.age = self.age;return copy;}// 实现协议方法,委托方会自动调用协议中的该方法- (id)mutableCopyWithZone:(NSZone *)zone{Teacher *copy = [[Teacher allocWithZone:zone] init];          copy.name = self.name;copy.age = self.age;return copy;}- (NSString *)description{return [NSString stringWithFormat:@"%@  %i", self.name, self.age];}@end// main.m#import "Teacher.h"Teacher *tch = [[Teacher alloc] init];tch.name = @"xiao xin";tch.age = 28;// 内容复制Teacher *tchCpy = [tch copy];// 内容复制Teacher *tchMCopy = [tch mutableCopy];tchCpy.age = 20;tchMCopy.age = 22;NSLog(@"%p", tch);// tchCpy 与 tch 的地址不同NSLog(@"%p", tchCpy);// tchMCopy 与 tch 的地址不同NSLog(@"%p", tchMCopy);NSLog(@"%@", tch);// tchCpy 与 tch 的实例变量的值不同NSLog(@"%@", tchCpy);// tchMCopy 与 tch 的实例变量的值不同NSLog(@"%@", tchMCopy);// Children.h// 遵守 NSCopying, NSMutableCopying 协议@interface Children : NSObject <NSCopying, NSMutableCopying>@property (nonatomic, copy) NSString *name;@property (nonatomic, assign) int age;@end// Children.m@implementation Children// 实现协议方法,委托方会自动调用协议中的该方法。- (id)copyWithZone:(NSZone *)zone{// 若有类继承此类,并且此方法在子类中可用id copy = [[[self class] allocWithZone:zone] init];[copy setName:self.name];[copy setAge:self.age];return copy;}// 实现协议方法,委托方会自动调用协议中的该方法。- (id)mutableCopyWithZone:(NSZone *)zone{// 若有类继承此类,并且此方法在子类中可用id copy = [[[self class] allocWithZone:zone] init];[copy setName:self.name];[copy setAge:self.age];return copy;}@end// GoodChildren.h@interface GoodChildren : Children@property (nonatomic, assign)int score;@end// GoodChildren.m@implementation GoodChildren// 实现协议方法,委托方会自动调用协议中的该方法。- (id)copyWithZone:(NSZone *)zone{                                      GoodChildren *copy = [super copyWithZone:zone];copy.score = self.score;return copy;}// 实现协议方法,委托方会自动调用协议中的该方法。- (id)mutableCopyWithZone:(NSZone *)zone{                               GoodChildren *copy = [super copyWithZone:zone];copy.score = self.score;return copy;}- (NSString *)description{return [NSString stringWithFormat:@"%@  %i  %d", self.name, self.age, self.score];}@end// main.m#import "GoodChildren.h"GoodChildren *gChild = [[GoodChildren alloc] init];gChild.name = @"xiao xin";gChild.age = 18;gChild.score = 88;// 内容复制GoodChildren *gChildCopy = [gChild copy];// 内容复制GoodChildren *gChildMCopy = [gChild mutableCopy];gChildCopy.age = 20;gChildMCopy.age = 22;gChildCopy.score = 100;gChildMCopy.score = 120;NSLog(@"%p", gChild);// gChildCopy 与 gChild 的地址不同NSLog(@"%p", gChildCopy);// gChildMCopy 与 gChild 的地址不同NSLog(@"%p", gChildMCopy);NSLog(@"%@", gChild);// gChildCopy 与 gChild 的实例变量的值不同NSLog(@"%@", gChildCopy);// gChildMCopy 与 gChild 的实例变量的值不同NSLog(@"%@", gChildMCopy);

转载于:https://www.cnblogs.com/QianChia/p/5782887.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/283970.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

三.选择结构(一)

1.if结构: if(条件){ 代码块 } 2.随机产生数: int randon (int)(Math.random()*10); 3.多重if选择结构: if(条件1){ 代码块1 }else if (条件2){ 代码块2 }else{ 代码块3 } 4.嵌套if选择结构: if(条件1){ if(条件2){ 代码块1 }else{ 代码块2 } }else{ 代码块3 } 转载于:https://…

为了高性能、超大规模的模型训练,这个组合“出道”了

点击上方蓝字关注我们&#xff08;本文阅读时间&#xff1a;3分钟)近年来&#xff0c;在大量数据上训练的基于 transformer 的大规模深度学习模型在多项认知任务中取得了很好的成果&#xff0c;并且被使用到一些新产品和功能背后&#xff0c;进一步增强了人类的能力。在过去五年…

SVN就是这么简单

什么是SVN SVN全称&#xff1a;Subversion&#xff0c;是一个开放源代码的版本控制系统 Svn是一种集中式文件版本管理系统。集中式代码管理的核心是服务器&#xff0c;所有开发者在开始新一天的工作之前必须从服务器获取代码&#xff0c;然后开发&#xff0c;最后解决冲突&…

SpringCloud必会知识点大全

为什么要学习Spring Cloud 在项目开发中随着业务越来越多&#xff0c;导致功能之间耦合性高、开发效率低、系统运行缓慢难以维护、不稳定。微服务 架构可以解决这些问题&#xff0c;而Spring Cloud是微服务架构最流行的实现. 1.微服务 微服务架构是使用一套小服务来开发单个应用…

thinkphp3.22 多项目配置

1.index.php if(version_compare(PHP_VERSION,5.3.0,<)) die(require PHP > 5.3.0 !); // 开启调试模式 建议开发阶段开启 部署阶段注释或者设为false define(APP_DEBUG,true); // 创建 //define(BIND_MODULE,Login); define(erp,true); // 定义应用目录 define(APP_PAT…

30分钟掌握 C#7

1. out 变量&#xff08;out variables&#xff09; 以前我们使用out变量必须在使用前进行声明&#xff0c;C# 7.0 给我们提供了一种更简洁的语法 “使用时进行内联声明” 。如下所示&#xff1a; 1 var input ReadLine(); 2 if (int.TryParse(input, out var result)) 3 …

在 C# 中如何检查参数是否为 null

前言前不久&#xff0c;微软宣布从 C# 11 中移除参数空值检查功能&#xff0c;该功能允许在方法开始执行之前&#xff0c;在参数名称的末尾提供参数空值检查&#xff08;!!操作符&#xff09;。那么&#xff0c;在 C# 中如何检查参数是否为 null 呢&#xff1f;1. null这个可能…

什么是Maven快照(SNAPSHOT)

本文来说下Maven的SNAPSHOT版本有什么作用 文章目录 问题解决 正式版本"abc-1.0"快照版本"abc-1.0-SNAPSHOT"本文小结问题 在使用maven进行依赖管理时&#xff0c;有的版本号后面会带有"-SNAPSHOT"&#xff0c;有什么作用呢&#xff1f; <dep…

带你剖析WebGis的世界奥秘----Geojson数据加载(高级)

前言&#xff1a;前两周我带你们分析了WebGis中关键步骤瓦片加载点击事件&#xff08;具体的看前两篇文章&#xff09;&#xff0c;下面呢&#xff0c;我带大家来看看Geojson的加载及其点击事件 Geojson数据解析 GeoJSON是一种对各种地理数据结构进行编码的格式。GeoJSON对象可…

如果要存ip地址,用什么数据类型比较好

在看高性能MySQL第3版&#xff08;4.1.7节&#xff09;时&#xff0c;作者建议当存储IPv4地址时&#xff0c;应该使用32位的无符号整数&#xff08;UNSIGNED INT&#xff09;来存储IP地址&#xff0c;而不是使用字符串。但是没有给出具体原因。为了搞清楚这个原因&#xff0c;查…

微软 .NET Core 3.1 年底将结束支持,请升级到.NET 6

微软近日宣布&#xff0c;将于 2022 年 12 月 13 日停止为 .NET Core 3.1 提供服务更新、安全修复和技术支持。.NET Core 是一个免费开源的、用于 Windows、Linux 和 macOS 操作系统的软件框架。该项目主要由微软员工通过 .NET 基金会开发&#xff0c;并在 MIT 许可下发布。202…

软件团队的模式选择

软件团队的模式分为&#xff1a;主治医生模式、明星模式、社区模式、业余剧团模式、秘密团队、特工团队、交响乐团模式、爵士乐模式、功能团队模式和官僚模式。 经过小组的讨论&#xff0c;我们决定选用交响乐团模式获得功能团队模式。 交响乐团模式的优点是种类多&#xff0c;…

Angular 2

1. Angular2 官网 https://angular.io/guide/quickstart Node.js 下载 https://nodejs.org/en/ 怎么在vs code中使用angualr2 https://code.visualstudio.com/docs/nodejs/angular-tutorial moment.js:(javacript日期处理库) http://momentjs.cn/ 2. ng2-hightCharts https://…

「Docker入门指北」容器很难理解?带你从头到尾捋一遍

文章目录 1. 初始虚拟化 &#x1f351; 虚拟化概念&#x1f351; 硬件虚拟化2. Docker容器 &#x1f351; Docker技术的诞生&#x1f351; 容器与虚拟化&#x1f351; 性能差别&#x1f351; Docker优势 编排有序高效易迁移快速部署3. 容器生态系统 &#x1f351; 核心技术 容器…

微服务:事务管理

几乎所有的信息管理系统都会涉及到事务&#xff0c;事务的目的是为了保证数据的一致性&#xff0c;这里说的一致性是数据库状态的一致性。说到数据库状态的一致性&#xff0c;相信大家都会想到 ACID &#xff1a;原子性&#xff08;Atomic&#xff09;&#xff1a;在一个事件的…

js - flex布局测试案例:完美居中

<span>I love flex layout!</span><style>body{display:flex;justify-content:center;align-items:center;font-size:3em;color:#00ffff;}</style>![enter image description here][1]<p>与自己为敌&#xff0c;</p><p>与自己为友&a…

操作数据库(对战小游戏)

创建数据库 1 create database duizhan2 go3 use duizhan4 go5 create table duizhan6 (7 Code varchar(20) not null primary key,8 Name varchar(20) not null,9 Sex varchar(20) not null, 10 Blood int, 11 Attack int, 12 Defence int, 13 Mingzhong…

8-Python3从入门到实战—基础之数据类型(集合-Sets)

Python从入门到实战系列——目录 集合的定义 集合&#xff08;set&#xff09;和字典类似&#xff0c;也是一组key的集合&#xff0c;但不存储value&#xff1b;由于key不能重复&#xff0c;所以&#xff0c;在set中&#xff0c;没有重复的key。创建一个set&#xff0c;需要提供…

Redis的那些事:一文入门Redis的基础操作

Redis是什么Redis&#xff0c;全称是Remote Dictionary Service,翻译过来就是&#xff0c;远程字典服务。redis属于nosql非关系型数据库。Nosql常见的数据关系&#xff0c;基本上是以key-value键值对形式存在的。Key-value: 就像翻阅中文字典或者单词字典&#xff0c;通过指定的…

10种提问型爆文标题句式 直接套用

如果你用1天的时间来写篇好文章&#xff0c;那你花掉半天时间想一个好标题都不过分&#xff01; 你是不是觉得我有点言过其实了&#xff1f;没关系&#xff0c;先来问你2个问题&#xff1a; 1、花了很长时间&#xff0c;写了一篇很牛的卖货推文&#xff0c;定稿后&#xff0c…