在ObjC中,什么是深浅拷贝?  深浅拷贝分别指深拷贝和浅拷贝,即 mutableCopy 和 copy 方法。  copy复制一个不可变对象,而 mutableCopy 复制一个 mutable 可变对象。

非容器类对象  如NSString,NSNumber等一类对象 
示例1:

// 非容器类对象
NSString *str = @"origin string";
NSString *strCopy = [str copy];
NSMutableString *mstrCopy = [str mutableCopy];
[mstrCopy appendString:@"??"]; // NSLog(@"array1 = %p", array1);
// NSLog(@"arrayCopy1 = %p", arrayCopy1);

查看内存可以发现,str和strCopy指向的是同一块内存区域,我们称之为弱引用(weak reference)。而mstrCopy是真正的复制,系统为其分配了新内存空间,保存从str复制过来的字符串值。从最后一行代码中修改这些值而不影 响str和strCopy中可证明。

示例2:

    NSMutableString *mstr = [NSMutableString stringWithString:@"origin"];
NSString *strCopy = [mstr copy];
NSMutableString *mstrCopy = [mstr copy];
NSMutableString *mstrMCopy = [mstr mutableCopy];
//[mstrCopy appendString:@"1111"]; //error
[mstr appendString:@""];
[mstrMCopy appendString:@""];

以上四个对象所分配的内存都是不一样的。而且对于mstrCopy,它所指向的其实是一个imutable对象,是不可改变的,所以会出错。这点要注意,好好理解。

小结: 
1.如果对一个不可变对象复制,copy是指针复制,即浅拷贝;而mutableCopy则是对象复制,即深拷贝。 
2.如果是对可变对象复制,都是深拷贝,但是copy复制返回的对象是不可变的。

容器类对象深浅复制 
比如NSArray,NSDictionary等。对于容器类本身,上面讨论的结论也适用的,下面探讨的是复制后容器内对象的变化。

示例3:

    /* copy返回不可变对象,mutablecopy返回可变对象 */
NSArray *array1 = [NSArray arrayWithObjects:@"a",@"b",@"c",nil];
NSArray *arrayCopy1 = [array1 copy];
//arrayCopy1是和array同一个NSArray对象(指向相同的对象),包括array里面的元素也是指向相同的指针
NSLog(@"array1 retain count: %d",[array1 retainCount]);    // 2
NSLog(@"array1 retain count: %d",[arrayCopy1 retainCount]); // 2 NSMutableArray *mArrayCopy1 = [array1 mutableCopy];
//mArrayCopy1是array1的可变副本,指向的对象和array1不同,但是其中的元素和array1中的元素指向的还是同一个对象。mArrayCopy1还可以修改自己的对象
[mArrayCopy1 addObject:@"de"];
[mArrayCopy1 removeObjectAtIndex:];

array1和arrayCopy1是指针复制,而mArrayCopy1是对象复制,符合前面示例1讨论的结论。mArrayCopy1可以改变其内的元素:删除或添加。但容器内的元素内容都是浅拷贝。

示例4

    NSArray *mArray1 = [NSArray arrayWithObjects:[NSMutableString stringWithString:@"a"],@"b",@"c",nil];
NSLog(@"mArray1 retain count: %d",[mArray1 retainCount]);
NSArray *mArrayCopy2 = [mArray1 copy];
NSLog(@"mArray1 retain count: %d",[mArray1 retainCount]);
// mArray1和mArrayCopy2指向同一对象,retain值+1。 NSMutableArray *mArrayMCopy1 = [mArray1 mutableCopy];
NSLog(@"mArray1 retain count: %d",[mArray1 retainCount]);
//mArrayCopy2和mArray1指向的是不一样的对象,但是其中的元素都是一样的对象——同一个指针 NSMutableString *testString = [mArray1 objectAtIndex:];
//testString = @"1a1";//这样会改变testString的指针,其实是将@“1a1”临时对象赋给了testString
[testString appendString:@" tail"];//这样以上三个数组的首元素都被改变了

由此可见,对于容器而言,其元素对象始终是指针复制。如果需要元素对象也是对象复制,就需要实现深拷贝。

示例5

NSArray *array = [NSArray arrayWithObjects:[NSMutableString stringWithString:@"first"] ,[NSString stringWithString:@"b"],@"c",nil];
NSArray *deepCopyArray=[[NSArray alloc] initWithArray: array copyItems: YES];
NSLog(@"array[2] = %@, deepCopyArray[2]=%@ ",[array objectAtIndex:], [deepCopyArray objectAtIndex:]); //输出值是一样的
NSLog(@"array[2] %p", [array objectAtIndex:]);
NSLog(@"deepCopyArray[2] %p", [deepCopyArray objectAtIndex:]);
//最后两个打印的log内存地址值是一样的 NSArray* trueDeepCopyArray = [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject: array]];

trueDeepCopyArray 是完全意义上的深拷贝,而deepCopyArray则不是,对于 deepCopyArray 内的不可变元素其还是指针复制。

自己实现深拷贝的方法 NSDictionaryMutableDeepCopy.h

#import <foundation /Foundation.h>
@interface NSDictionary(MutableDeepCopy)
- (NSMutableDictionary *)mutableDeepCopy;
@end

NSDictionaryMutableDeepCopy.m

#import "NSDictionaryMutableDeepCopy.h"
@implementation NSDictionary(MutableDeepCopy)
- (NSMutableDictionary *)mutableDeepCopy {
NSMutableDictionary *ret = [[NSMutableDictionary alloc]
initWithCapacity:[self count]];
NSArray *keys = [self allKeys];
for (id key in keys) {
id oneValue = [self valueForKey:key];
id oneCopy = nil;
if ([oneValue respondsToSelector:@selector(mutableDeepCopy)]) {
oneCopy = [oneValue mutableDeepCopy];
}
else if ([oneValue respondsToSelector:@selector(mutableCopy)]) {
oneCopy = [oneValue mutableCopy];
}
if (oneCopy == nil) {
oneCopy = [oneValue copy];
}
[ret setValue:oneCopy forKey:key];
}
return ret;
}

使用类别方法来实现 
如果是我们定义的对象,那么我们自己要实现NSCopying,NSMutableCopying这样就能调用copy和mutablecopy了。举个例子

@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 = -;
}
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, , zone);
copy->name = [self.name mutableCopy];
copy->age = age;
return copy;
}
@end



ios学习路线—Objective-C(深浅拷贝)的更多相关文章

  1. ios 学习路线总结

    学习方法 面对有难度的功能,不要忙着拒绝,而是挑战一下,学习更多知识. 尽量独立解决问题,而不是在遇到问题的第一想法是找人. 多学习别人开源的第三方库,能够开源的库一定有值得学习的地方,多去看别的大神 ...

  2. iOS开发——iOS学习路线

    iOS学习路线 版权声明:欢迎转载,请贴上源地址:http://www.cnblogs.com/iCocos/(iOS梦工厂) 一:自学初步学习路线 二:高级完整学习路线 三:完整知识与能力体系 思维 ...

  3. python 学习笔记5(深浅拷贝与集合)

    拷贝 我们已经详细了解了变量赋值的过程.对于复杂的数据结构来说,赋值就等于完全共享了资源,一个值的改变会完全被另一个值共享. 然而有的时候,我们偏偏需要将一份数据的原始内容保留一份,再去处理数据,这个 ...

  4. iOS学习路线

    这个学习路线必须发布到首页候选区.这个学习路线必须发布到首页候选区.这个学习路线必须发布到首页候选区.这个学习路线必须发布到首页候选区.这个学习路线必须发布到首页候选区.这个学习路线必须发布到首页候选 ...

  5. 学习--->更新集合/内存/深浅拷贝

     一.计算机基础 1..软件(应用程序) 2.解释器/编译器 - 解释型语言:将代码每一行传递给计算机一行,常用编程语言python,PHP,Ruby. - 编译型语言:将代码完全执行完后会形成一个文 ...

  6. (2018干货系列十一)最新iOS学习路线整合

    怎么学iOS iOS是由苹果公司开发的移动操作系统,以xcode为主要开发工具,具有简单易用的界面.令人惊叹的功能,以及超强的稳定性,已经成为iPhone.iPad 和iPod touch 的强大基础 ...

  7. ios学习路线—Objective-C(Runtime消息机制)

    RunTime简称运行时.就是系统在运行的时候的一些机制,其中最主要的是消息机制.对于C语言,函数的调用在编译的时候会决定调用哪个函数( C语言的函数调用请看这里 ).编译完成之后直接顺序执行,无任何 ...

  8. ios学习路线—Objective-C(新特性)

    1.方法顺序无关 Objective-C类由声明文件h和实现文件m组成,所有的public方法都在h文件中声明,private方法可以写在m文件中,但是在早期的编译环境中需要注意方法的顺序,例如下面的 ...

  9. ios学习路线—Objective-C(属性修饰符)

    readonly: 此标记说明属性是只读的,默认的标记是读写,如果你指定了只读,在@implementation中只需要一个读取器.或者如果你使用@synthesize关键字,也是有读取器方法被解析. ...

随机推荐

  1. 行内元素和块级元素的具体区别是什么?inline-block是什么?(面试题目)

    一,行内元素与块级元素的区别: 1.行内元素与块级元素直观上的区别二.行内元素与块级元素的三个区别 行内元素会在一条直线上排列(默认宽度只与内容有关),都是同一行的,水平方向排列. 块级元素各占据一行 ...

  2. CSS 内外边距 float positio属性

    一.外边距和内边 margin:            用于控制元素与元素之间的距离 外边距:margin的最基本用途就是控制元素周围空间的间隔,从视觉角度上达到相互隔开的目的. padding:   ...

  3. zabbix系列之五——安装后配置一

    https://www.zabbix.com/documentation/3.4/manual/appliance Configuration 1Hosts and host groups Overv ...

  4. ExpressRoute 合作伙伴和对等位置

    本文中的表格提供有关 ExpressRoute 连接提供商.ExpressRoute 地理覆盖范围.通过 ExpressRoute 支持的 Azure 服务以及 ExpressRoute 系统集成商 ...

  5. jetty8 中的异常 There is an error in invoking javac. A full JDK (not just JRE) is required...

    在jetty文件夹下的start.ini文件里有这么一行"-Dorg.apache.jasper.compiler.disablejsr199=true"注释,把这个注释去掉,再启 ...

  6. 配置consul为windows服务

    安装consul并配置为系统服务下载地址https://www.consul.io/downloads.html 配置系统服务1.拷贝consul.exe的目录 如:E:\Consul\consule ...

  7. 固定UILabel宽度分行显示

    固定UILabel宽度分行显示 这种小伎俩估计都被用烂了,笔者给大家提供一个category文件,供大家简单设置哦. 各种富文本效果哦(普通文本也是可以用的呢): 3行,固定宽度200 2行,固定宽度 ...

  8. Linux 系统的网络基础_【all】

    网络基础 1.网线:568B: 白橙 橙色 白绿 蓝色 白蓝 绿色 白棕 棕色 2.交换机:电信号转发的网络设备,它可以为接入交换机的任2个网络节点设备提供电信号通信 3.路由器:连接局域网,广域网的 ...

  9. EF CodeFirst下的自动迁移

    当我们修改数据模型,添加一个如下字段 再次运行程序,会因为数据库结构与模型不一致而报错 为解决以上错误可以采取以下三种方式 1.  删除数据库,重新运行站点,会重新生成数据库,这样就会丢失数据 2.  ...

  10. September 30th 2017 Week 39th Saturday

    The simplest answer is often the correct one. 最简单的答案通常是最正确的答案. Simplest is always best. Sometimes yo ...