参考:

http://blog.csdn.net/qq_17007915/article/details/50503043

http://www.cnblogs.com/ludashi/p/3894151.html

iOS开发之深拷贝与浅拷贝

打个比方,对于同一个抽屉里的蛋糕,深拷贝时制作一份新的蛋糕存起来,浅拷贝是复制一把打开抽屉钥匙存起来。

深拷贝拷贝的是内容,浅拷贝拷贝的是指针。用一句简单的话来说就是浅拷贝,是对指针的拷贝,拷贝后两个指针指向同一个内存空间,深拷贝不但对指针进行拷贝,而且对指针指向的内容进行拷贝,经深拷贝后的指针是指向两个不同地址的指针。

理解一:

浅拷贝:是拷贝操作后,生成了另一个指针也指向了同一个地址。

深拷贝:拷贝操作后,是真正的复制了一份,另一个指针指向了,拷贝后的地址。如下图:A代表原有的指针,B代表拷贝的指针。

       

--------浅拷贝----------------------深拷贝------

从上图中可以看到,浅拷贝(浅复制)中如果其中A指针改变了所指向的地址的内容,那么B指针也指向被修改后的内容。如果有些地方用到B指针,即便A指向的内容发生变化,也不希望B受到影响,则需要用深拷贝,真正复制一份A指向的内容,B指向复制后的值,这样即使A指向的内容变化了,B也不会产生影响。网上也有人通俗理解为:浅复制好比你和你的影子,你完蛋,你的影子也完蛋。深复制好比你和你的克隆人,你完蛋,你的克隆人还活着。

理解二:

深拷贝和浅拷贝的本质是地址相同,就是浅拷贝,地址不同就是深拷贝。

ios开发过程中,大体上会区分为对象和容器两个概念,对象的copy是浅拷贝,mutablecopy是深拷贝。容器也参照如上方法,但是需要记住,容器的包含对象的拷贝,无论使用copy,还是mutablecopy都将是浅拷贝。要想实现对象的深拷贝,必须自己提供拷贝的方法。自己提供的方法见下面的注意点。

三. 理解三(代码方式)

NSArray *array = [NSArray arrayWithObjects:@"one",@"two", nil];

NSMutableArray *array1 = [array copy];

[array1 addObject:@"three"];

// 这段代码是错误的。array1,通过copy进行的是浅拷贝,即并没有真正复制array,而是也指向了array,此时array是不可变数组,无法进行新数据的添加

NSArray *array=[NSArray arrayWithObjects:@"one",@"two", nil];

NSMutableArray *array2=[array mutableCopy];

[array2 addObject:@"three"];

// 这段代码是正确的,array2通过mutableCopy进行的是深拷贝,即把array真正复制了一份,并且复制后,变为了NSMutableArray ,此时array2是可变数组,可以添加数据。

注意点:(1)当使用mutableCopy时,不管源对象是否可变,副本是可变的,并且实现真正意义上的拷贝。

当我们使用copy一个可变对象时,副本对象是不可变的。

(2)要想实现对象的自定义拷贝,必须实现NSCopying,NSMutableCopying协议,实现该协议的copyWithZone方法和mutableCopyWithZone方法。深拷贝和浅拷贝的区别就在于copyWithZone方法的实现。

UI是iOS的UI库,用objective-c封装的,一般用于普通的视图和控制器,如UIView、UIImageView、UITableViewController等。

NS是objc的基础库

CG,CF等是比较底层的C语言的库

可以理解UIFont就是用objc封装过的CGFont,用起来方便些

1. 非容器不可变对象,比如NSString

2. 非容器可变对象:比如NSMutableString

3. 容器类不可变对象: 比如NSArray

4. 容器类可变对象: 比如NSMutableArray

NSLog(@“打印对象引用计数:%ld",CFGetRetainCount((__bridgeCFTypeRef)(arrayCopy1)));

NSLog(@"打印指针内存地址:%x",&ggg);

NSLog(@"打印指针所指向对象的地址:%p",ggg);

1.非容器 + 不可变对象 + retain + copy + mutableCopy

NSLog(@"非容器类不可变对象拷贝NSString");

NSString*str =@"ludashi";

// retain

NSString*str1 =[strretain];

// copy

NSString*str2 =[strcopy];

// mutableCopy

NSString*str3 =[strmutableCopy];

// 分别输出指针内存地址,指针所指向对象的地址,对象引用计数

NSLog(@"str指针内存地址:%x——:指针所指向对象的地址:%p——对象引用计数:%d”,&str,str,str.retainCount);

NSLog(@"str1指针内存地址:%x——:指针所指向对象的地址:%p——对象引用计数:%d",&str1,str1,str1.retainCount);

NSLog(@"str2指针内存地址:%x——:指针所指向对象的地址:%p——对象引用计数:%d",&str2,str2,str2.retainCount);

NSLog(@"str2指针内存地址:%x——:指针所指向对象的地址:%p——对象引用计数:%d",&str3,str3,str3.retainCount);

2.非容器 + 可变对象 + retain + copy + mutableCopy

NSLog(@"非容器类的可变对象拷贝");

NSMutableString*s =[NSMutableString stringWithFormat:@"ludashi"];

//把s通过retain的方式把值 赋给s1;

NSMutableString*s1 =[sretain];

//把s通过copy的方式把值赋给s2;

NSMutableString*s2 =[scopy];

//把s通过mutableCopy的方式把值赋给s3

NSMutableString*s3 =[smutableCopy];

NSLog(@"s指针内存地址:%x——:指针所指向对象的地址:%p——对象引用计数:%d”,&str,str,str.retainCount);

NSLog(@"s1指针内存地址:%x——:指针所指向对象的地址:%p——对象引用计数:%d",&str1,str1,str1.retainCount);

NSLog(@"s2指针内存地址:%x——:指针所指向对象的地址:%p——对象引用计数:%d",&str2,str2,str2.retainCount);

NSLog(@"s2指针内存地址:%x——:指针所指向对象的地址:%p——对象引用计数:%d",&str3,str3,str3.retainCount);

运行结果分析:

1.retian对对可变对象为浅拷贝

2.copy对可变对象非容器类为深拷贝

3.mutableCopy对可变非容器类为深拷贝

3.容器类 +  非可变对象 + retain + copy + mutableCopy

下面对容器类的非可变对象进行测试,有程序的运行结果可知当使用mutableCopy时确实返回了一个新的容器(由内存地址可以看出),但从容器对象看而言是容器的深拷贝,但从输出容器中的元素是容器的浅拷贝。

NSMutableString *string = [NSMutableString stringWithFormat:@"ludashi"];

//第二种:容器类不可变对象拷贝

NSLog(@"容器类不可变对象拷贝");

NSArray *array = [NSArray arrayWithObjects:string,@"b", nil];

//把array通过retain方式把值赋给array1

NSArray *array1 = [array retain];

//把array通过copy的方式把值赋给array2

NSArray *array2 = [array copy];

//把array通过mutableCopy方式把值赋给array3

NSArray *array3 = [array mutableCopy];

NSLog(@"array指针内存地址:%x——:指针所指向对象的地址:%p——对象引用计数:%d”,&array,array,array.retainCount);

NSLog(@"array1指针内存地址:%x——:指针所指向对象的地址:%p——对象引用计数:%d",&array1,array1,array1.retainCount);

NSLog(@"array2指针内存地址:%x——:指针所指向对象的地址:%p——对象引用计数:%d",&array2,array2,array2.retainCount);

NSLog(@"array3指针内存地址:%x——:指针所指向对象的地址:%p——对象引用计数:%d",&array3,array3,array3.retainCount);

//打印输出每个可变容器中元素的地址

NSLog(@"打印输出每个可变容器中元素的地址");

NSLog(@" array[0] = %p", array[0]);

NSLog(@"array1[0] = %p", array1[0]);

NSLog(@"array2[0] = %p", array2[0]);

NSLog(@"array3[0] = %p", array3[0]);

4.容器类 +  可变对象 + retain + copy + mutableCopy

面对容器类的可变对象进行测试,copy和mutableCopy对于容器本身是深拷贝,原因是返回了一个新的容器地址,但对于容器中的元素仍然是浅拷贝。

NSLog(@"********************************************\n\n\n\n");

//第四种:容器类的可变对象的拷贝,用NSMutableArray来实现

NSLog(@"容器类的可变对象的拷贝");

NSMutableArray *m_array = [NSMutableArray arrayWithObjects:string, nil];

//把m_array通过retain把值赋给m_array1

NSMutableArray *m_array1 = [m_array retain];

//把m_array通过copy把值赋给m_array2

NSMutableArray *m_array2 = [m_array copy];

//把m_array通过mytableCopy把值赋给m_array3

NSMutableArray *m_array3 = [m_array mutableCopy];

NSLog(@"m_array指针内存地址:%x——:指针所指向对象的地址:%p——对象引用计数:%d”,&m_array,m_array,m_array.retainCount);

NSLog(@"m_array1指针内存地址:%x——:指针所指向对象的地址:%p——对象引用计数:%d",&m_array1,m_array1,m_array1.retainCount);

NSLog(@"m_array2指针内存地址:%x——:指针所指向对象的地址:%p——对象引用计数:%d",&m_array2,m_array2,m_array2.retainCount);

NSLog(@"m_array3指针内存地址:%x——:指针所指向对象的地址:%p——对象引用计数:%d",&m_array3,m_array3,m_array2.retainCount);

//打印输出每个可变容器中元素的地址

NSLog(@"打印输出每个可变容器中元素的地址");

NSLog(@" m_array[0] = %p", m_array[0]);

NSLog(@"m_array1[0] = %p", m_array1[0]);

NSLog(@"m_array2[0] = %p", m_array2[0]);

NSLog(@"m_array3[0] = %p", m_array3[0]);

上面的代码以及代码的运行结果翻来复去就是在验证下面的结论:

1.retain:始终是浅复制。引用计数每次加一。返回对象是否可变与被复制的对象保持一致。

2.copy:对于可变对象为深复制,引用计数不改变;对于不可变对象是浅复制, 引用计数每次加一。始终返回一个不可变对象。  

3.mutableCopy:始终是深复制,引用计数不改变。始终返回一个可变对象。

第五、浅copy和深copy

浅复制尽复制对象本身,对象里的属性、包含的对象不做复制

深复制复制全部,包括对象的属性和其他对象

Foundation框架支持复制的类,默认是浅复制

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

NSMutableArray *array = [[NSMutableArray alloc] init];

for(int i=0;i<3;i++)

{

NSObject *obj = [[NSObject alloc] init];

[array addObject:obj];

[obj release];

}

for(NSObject *obj1 in array)

{

NSLog(@"地址为 %p,引用计数是 %ld",obj1,obj1.retainCount);

}

NSMutableArray *array2=[array copy];

for(NSObject *obj2 in array2)

{

NSLog(@"地址为 %p,引用计数是 %ld",obj2,obj2.retainCount);

}

2013-09-3017:28:01.492 FDAS[681:303] 地址为 0x1001081f0,引用计数是 1

2013-09-3017:28:01.506 FDAS[681:303] 地址为 0x100108230,引用计数是 1

2013-09-3017:28:01.506 FDAS[681:303] 地址为 0x100108240,引用计数是 1

2013-09-3017:28:01.507 FDAS[681:303] 地址为 0x1001081f0,引用计数是 2

2013-09-3017:28:01.507 FDAS[681:303] 地址为 0x100108230,引用计数是 2

2013-09-3017:28:01.507 FDAS[681:303] 地址为 0x100108240,引用计数是 2

3. 自定义类对象之间的深浅拷贝问题

在Objective-C中并不是所有的类都支持拷贝;只有遵循NSCopying协议的类,才支持copy拷贝,只有遵循NSMutableCopying协议的类,才支持mutableCopy拷贝。如果没有遵循拷贝协议,拷贝时会出错。

如果我们想再我们自定义的类中支持copy和mutableCopy那么我们就需要使我们定义的类遵循NSCopying和NSMutableCopying协议,代码如下:

@interface MyObj : NSObject<NSCopying,NSMutableCopying>

{

NSMutableString *name;

NSString *imutableStr;

int age;

}

@property (nonatomic, retain) NSMutableString *name;

@property (nonatomic, retain) NSString *imutableStr;

@property (nonatomic) int age;

@end

@implementation MyObj

@synthesize name;

@synthesize age;

@synthesize imutableStr;

- (id)init

{

if (self = [super init])

{

self.name = [[NSMutableString alloc]init];

self.imutableStr = [[NSString alloc]init];

age = -1;

}

return self;

}

- (void)dealloc

{

[name release];

[imutableStr release];

[super dealloc];

}

- (id)copyWithZone:(NSZone *)zone

{

MyObj *copy = [[[self class] allocWithZone:zone] init];

copy->name = [name copy];

copy->imutableStr = [imutableStr copy];

//       copy->name = [name copyWithZone:zone];;

//       copy->imutableStr = [name copyWithZone:zone];//

copy->age = age;

return copy;

}

- (id)mutableCopyWithZone:(NSZone *)zone

{

MyObj *copy = NSCopyObject(self, 0, zone);

copy->name = [self.name mutableCopy];

copy->age = age;

return copy;

}

(0056)iOS开发之深拷贝与浅拷贝相关推荐

  1. IOS中的深拷贝和浅拷贝

    标签: 什么是深拷贝?什么是浅拷贝? 为什么经常看到字符串属性要这样定义,那个copy是神马意思? @property(nonatomic,copy)NSString* name; 为什么下面的写法是 ...

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

    深拷贝和浅拷贝这个问题在面试中常常被问到,而在实际开发中,只要稍有不慎,就会在这里出现问题.尤其对于初学者来说,我们有必要来好好研究下这个概念.我会以实际代码来演示,相关示例代码上传至 这里 . 首先 ...

  3. 深拷贝与浅拷贝(mutableCopy与Copy)详解 iOS

    深拷贝与浅拷贝(mutableCopy与Copy)详解 iOS ios中并不是所有的对象都支持copy,mutableCopy,遵守NSCopying 协议的类可以发送copy消息,遵守NSMutab ...

  4. iOS开发几年了,你清楚OC中的这些东西么!!!?

    iOS开发几年了,你清楚OC中的这些东西么!!!? 前言 几年前笔者是使用Objective-C进行iOS开发, 不过在两年前Apple发布swift的时候,就开始了swift的学习, 在swift1 ...

  5. iOS开发知识点总结

    main文件做了这几件事:1. 创建当前的应用程序2. 根据4个参数的最后为应用程序设置代理类(默认情况下是AppDelegate)3. 将appDelegate 和 应用程序 建立关联(指定代理,) ...

  6. iOS开发笔记之八十一——2020 iOS面试总结《一》之干货篇

    ******阅读完此文,大概需要5分钟****** 这是我毕业之后第三次开始找工作了,适逢2019年底,我清楚地知道,iOS开发已经不是很景气了,尽管自己有名校以及大厂背景,但是自己一点都没有把握,自 ...

  7. 校园招聘iOS开发岗位面试题集锦(2017)

    转发自:  http://blog.csdn.net/chenyufeng1991/article/details/53472284#comments 一.搜狐快站 1.谈谈你做过的项目: 2.项目中 ...

  8. 2017秋季校园招聘iOS开发岗位面试题集锦

    笔者参加了2017秋季不少的校招iOS岗位面试,下面我把这些面试题都贴出来和大家共勉: 一.搜狐快站 1.谈谈你做过的项目: 2.项目中最有成就感的部分: 3.倒计时如何实现?(NSTimer,还有其 ...

  9. 互联网公司iOS开发工程师面试必看(最全知识点梳理)

    序言 目前形势,参加到iOS队伍的人是越来越多,甚至已经到供过于求了.今年,找过工作人可能会更深刻地体会到今年的就业形势不容乐观,加之,培训机构一火车地向用人单位输送iOS开发人员,打破了生态圈的动态 ...

最新文章

  1. Linux查看和剔除当前登录用户详细教程
  2. 安装Terminator和快捷键使用
  3. MongoDB数据库--扩展Base64,算法
  4. java创建日程到期提醒_Mac用户必备日程时间管理器,有计划有效率的人生才算完美!...
  5. P1803 凌乱的yyy / 线段覆盖
  6. Stark 组件:快速开发神器 —— 页面显示
  7. c语言exit_看了这几个C语言例子,你一定会说5个哇塞,声音一次比一次大
  8. “练好内功坚持被集成”,阿里云发布SaaS加速器
  9. IDEA解决maven多module出现多root的问题
  10. PyTorch学习—11.权值初始化
  11. java秒数格式转换_Java中整数(秒数)转换为时分秒格式(xx:xx:xx)
  12. 深度学习:Image Object Detection方法
  13. mysql 5.6 在线DDL
  14. 【matlab算法原理详解】车牌识别算法
  15. leetcode--打家劫舍
  16. 域名whois查询违规吗_WHOIS域ID隐私保护如何工作? 我需要域名WHOIS隐私吗?
  17. Linux下安装Adobe Flash Player插件(Firefox)
  18. date_histogram
  19. react 使用 swiper
  20. 计算机教师的应用计划书,教师信息技术个人提升计划

热门文章

  1. echarts 地图 免费离线js,json包分享
  2. MySQL用户管理、常用sql语句、数据库备份
  3. docker~Dockerfile优化程序的部署
  4. 第六十一节,html超链接和路径
  5. 【转】【React Native开发】
  6. 简单剖析智能指针的思想
  7. OAuth2.0 基础概述
  8. 通过PRINT过程制作报表
  9. MS-SQL数据库开发—精典
  10. 算法-- 删除排序链表中的重复元素(Java)