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;
}
- 在定义对象要实现拷贝,需要遵守NSCoping与NSMutableCoping协议,并实现以下方法
OC语言-08-深拷贝与浅拷贝详解(示例)的更多相关文章
- OC细节 - 1.深拷贝与浅拷贝详解
概述 拷贝:复制一个与源对象内容相同的对象 实现拷贝,需要遵守以下两个协议 NSCopying NSMutableCopying 拷贝返回对象的种类 可变,mutableCopy消息返回的对象 不可变 ...
- 【转】 c++拷贝构造函数(深拷贝,浅拷贝)详解
c++拷贝构造函数(深拷贝,浅拷贝)详解 2013-11-05 20:30:29 分类: C/C++ 原文地址:http://blog.chinaunix.net/uid-28977986-id-3 ...
- 【C++】拷贝构造函数(深拷贝,浅拷贝)详解
一.什么是拷贝构造函数 首先对于普通类型的对象来说,它们之间的复制是很简单的,例如: ; int b = a; 而类对象与普通对象不同,类对象内部结构一般较为复杂,存在各种成员变量. 下面看一个类对 ...
- **Python中的深拷贝和浅拷贝详解
Python中的深拷贝和浅拷贝详解 这篇文章主要介绍了Python中的深拷贝和浅拷贝详解,本文讲解了变量-对象-引用.可变对象-不可变对象.拷贝等内容. 要说清楚Python中的深浅拷贝,需要 ...
- javascript实现引用数据类型的深拷贝和浅拷贝详解
关于引用类型值的详解,请看另一篇随笔 https://www.cnblogs.com/jinbang/p/10346584.html 深拷贝和浅拷贝,也就是引用数据类型栈和堆的知识点.深浅拷贝的原型都 ...
- c++拷贝构造函数(深拷贝,浅拷贝)详解
一.什么是拷贝构造函数 首先对于普通类型的对象来说,它们之间的复制是很简单的,例如: ; int b=a; 而类对象与普通对象不同,类对象内部结构一般较为复杂,存在各种成员变量. 下面 ...
- python的拷贝方式以及深拷贝,浅拷贝详解
python的拷贝方法有:切片方法, 工厂方法, 深拷贝方法, 浅拷贝方法等. 几种方法都可以实现拷贝操作, 具体区别在于两点:1.代码写法不同. 2.内存地址引用不同 代码演示: import co ...
- C++ 深拷贝和浅拷贝详解
前言 在对象拷贝过程中,如果没有自定义拷贝构造函数,系统会提供一个缺省的拷贝构造函数,缺省的拷贝构造函数对于基本类型的成员变量,按字节复制,对于类类型成员变量,调用其相应类型的拷贝构造函数. 位拷贝( ...
- Go语言Slice作为函数参数详解
Go语言Slice作为函数参数详解 前言 首先要明确Go语言中实质只有值传递,引用传递和指针传递是相对于参数类型来说. 个人认为上诉的结论不对,把引用类型看做对指针的封装,一般封装为结构体,结构体是值 ...
随机推荐
- Linux动态库的搜索路径
下面是目录结构: pengdl@localhost:~$ tree test/test/├── fun.c├── Fun.h└── t1 └── main.c 1 directory, 3 fi ...
- LeetCode——LRU Cache
Description: Design and implement a data structure for Least Recently Used (LRU) cache. It should su ...
- IOS高级编程之二:IOS的数据存储与IO
一.应用程序沙盒 IOS应用程序职能在系统为该应用所分配的文件区域下读写文件,这个文件区域就是应用程序沙盒.所有的非代码文件如:图片.声音.映象等等都存放在此. 在mac中command+shift+ ...
- jQuery实现星星评分功能
一.这是我做的调查问卷中的一个功能.(第三方MVC框架) 二.功能说明:1.用户点击星星,将值放到隐藏域中.2.用户可以重新点击星星修改回答. 前台JS代码: <script type=&quo ...
- SignalR简单示例教程入门版
上周五最后一天在公司上班,无聊之余就想做点什么.介于之前有人让我做个简易版的在线聊天的,于是乎就打算花一天时间来弄下关于SignalR的简单教程制作一个在线的聊天的. 1:前端用了国产的一个MVVM框 ...
- 重新想象 Windows 8.1 Store Apps (72) - 新增控件: AppBar, CommandBar
[源码下载] 重新想象 Windows 8.1 Store Apps (72) - 新增控件: AppBar, CommandBar 作者:webabcd 介绍重新想象 Windows 8.1 Sto ...
- MySQL常用SQL语句
一.数据库操作 1.创建数据库: Mysql> CREATE DATABASE databaseName; Mysql数据库的数据文件默认存放在/usr/local/mysql/var/目录下, ...
- [moka收藏]php正则表达式验证
手机号验证规则[['mobile'], 'match','pattern' =>"/^1[34578]\\d{9}$/"], [['sendmail_limit'],'mat ...
- java四大域总结
最近学完了web部分,发现有些地方总是单个容易理解,可是把所有的放在一起来大杂烩,总是有那么几个知识点容易混淆.其实网上的资料已经够多了,虽然也不乏辛劳的搬运工.可是最终的目的不就是要我们自身理解吗? ...
- HTML5的新特性
HTML5 中的一些有趣的新特性: 用于绘画的 canvas 元素 用于媒介回放的 video 和 audio 元素 对本地离线存储的更好的支持 新的特殊内容元素,比如 article.footer. ...