前言

  • 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

iOS - OC Copy 拷贝相关推荐

  1. iOS - OC 面向对象语法

    1.类 1)根类:因为类 NSObject 是层次结构的最顶层,因此称为根类. 可以将类称为子类(subclass)和父类(superclass),也可以将类称为子类和超类. 2)分类/类别(cate ...

  2. IOS OC项目的单例模式

    IOS OC项目的单例模式 采用GCD方式书写单例,苹果官方示例代码也是这样写的,并打印一下地址,看看比较new出来的对象的地址是否相同. 提供一个类方法,供外部访问方便. @interface Ne ...

  3. 1.4.1bat脚本命令COPY 拷贝 复制到

    文员.网管必会技能:Windows命令行bat/cmd批处理脚本的编写应用之文件管理应用 1.4.1bat脚本命令COPY 拷贝 复制到 对于文件管理批处理: 新建_MD 列表_DIR 命名_REN ...

  4. iOS - OC iOS 开发体系

    1.iOS 开发技术体系 iOS 开发技术体系图: 层级 主要框架 Cocoa Touch UIKit 等 Media Core Graphics .OpenGl ES.Core Animation ...

  5. iOS OC与JS交互(WebView监听事件)

    在iOS应用的开发过程中,我们经常会使用到WebView,当我们对WebView进行操作的时候,有时会需要进行源生的操作.那么我记下来就与大家分享一下OC与JS交互. 首先先说第一种方法,并没有牵扯O ...

  6. iOS中copy,retain,strong,assign,weak的区别以及使用

    使用assign: 对基础数据类型 (NSInteger)和C数据类型(int, float, double, char,等) 使用copy: 对NSString 使用retain: 对其他NSObj ...

  7. iOS OC消除黄色警告⚠️ (不断的更新中...)

    开发一个项目时,难免会产生很多警告,一些是第三方或是老代码不再被支持造成的,但并不影响使用,这些警告其实可以直接隐藏掉!还有一些警告可能是系统方法弃用.不兼容指针类型.未使用变量.未使用default ...

  8. iOS OC语言(二) 类

    前言 类 是具有相同特征和行为的事物的抽象  万事万物皆对象 对象是类的实例 类是对象的类型 面向对象的特点分为: 封装 继承 多态  如何看懂OC中的一个类 在OC中  一个类中的成员, 分为实例变 ...

  9. iOS assign copy retain...含义

    assign: 简单赋值,不更改索引计数 copy: 建立一个索引计数为1的对象,然后释放旧对象 retain:释放旧的对象,将旧对象的值赋予输入对象,再提高输入对象的索引计数为1 Copy其实是建立 ...

最新文章

  1. 第八周实践项目8 稀疏矩阵的三元组表示的实现及应用
  2. 百度ueditor编辑器注入漏洞修补查杀程序
  3. html的meta属性
  4. SAP CRM WebClient UI cross component跳转中有一个硬编码的CROSSNAV
  5. linux fpga通信,基于Linux的FPGA通信技术研究与实现
  6. php文件写入加1,PHP关于文件与目录(1) 写入文件 文件权限 三、锁定文件
  7. bigdecimal取小数部分_小数精度丢失问题分析和解决
  8. 《天际友盟DRP数字风险防护报告(2021年上半年)》重磅发布
  9. ROS中阶笔记(四):机器人仿真—Gazebo物理仿真环境搭建(重点)
  10. net user test 123456 /add
  11. Vue登录注册,并保持登录状态 1
  12. GDI+ 保存HDC为位图文件
  13. Emacs中打造强大的Python IDE
  14. .net reactor使用教程(4)——.net reactor针对De4Dot脱壳工具的应对
  15. 最速下降法matlab全局最小值_MATLAB实现最速下降法
  16. 清华大学学术答辩通用PPT模板
  17. autosar-Layered Software Architecture
  18. OutMan——C语言中的冒泡排序、选择排序、折半查找以及指针的介绍
  19. angular directive 入门
  20. 基于Java毕业设计智友少儿编程学习平台源码+系统+mysql+lw文档+部署软件

热门文章

  1. [原]Jenkins(二十) jenkins再出发之Error: Opening Robot Framework log failed
  2. 华为2018软件岗笔试题解题思路和源代码分享
  3. 虚拟机中centos安装gcc
  4. Cluster_analysis
  5. 对使用CodeSmith模板生成NHibernate的代码的分析
  6. oracle t7-2报价,Sun/Oracle T7-2服务器主板7315607全新7318270原装7318240
  7. 计算机和外部通信方式,计算机和外部的通信方式
  8. android navigation bar高度,Android获取屏幕真实高度包含NavigationBar(底部虚拟按键)
  9. Excel中这四个常出错的地方,你一定中过!
  10. 后端:SpringBoot集成Swagger-Bootstrap-UI,界面美观!