iOS 深拷贝与浅拷贝详解

一、基本概念

浅拷贝

浅拷贝只是对object对象指针进行拷贝,不会开辟新的内存。与数据源指向的是同一内存。例如copyA = [A copy]capyAA指向的是同一内存,A的值变化,copyA的值也会发生变化。

copy方法做的是浅拷贝。

深拷贝

深拷贝会开辟新的内容,然后对原数据进行复制,新object对象与数据源指向的是不同的内存,对数据源操作不会影响新object对象。例如 mutableCopyA = [A mutableCopy]mutableCopyAA指向的是两块不同的内存,A的值发生变化不会影响到mutableCopyA的值。

mutableCopy方法做的是深拷贝。

二、不同对象类型的深拷贝和浅拷贝

NSString 和 NSMutableString

1、概述

分别创建一个NSStringNSMutableString类型字符串,然后用copymutableCopy,创建新的对象,查看对象指针地址和对象地址的变化。

同时用NSMutableString类型接收NSString对象copymutableCopy之后的值,并操作appendString,测试是否有问题。

对于NSMutableString类型copymutableCopy之后同样操作appendString,测试是否有问题。

2、示例分析
// 不可变字符串
    NSString *str = @"hello World";
    NSString *strCopy = [str copy];
    NSString *strMutableCopy = [str mutableCopy];
    
    NSLog(@"不可变字符串  copy 和 mutableCopy的区别");
    NSLog(@"                对象地址     对象指针地址   ");
    NSLog(@"     string: %p , %p", str, &str);
    NSLog(@"       copy: %p , %p", strCopy, &strCopy);
    NSLog(@"mutalbeCopy: %p , %p", strMutableCopy, &strMutableCopy);

运行结果
运行结果

// 可变字符串
    NSMutableString *mutableString = [NSMutableString stringWithString:@"hello world"];
    NSMutableString *mutableStringCopy = [mutableString copy];
    NSMutableString *mutableStringMutableCopy = [mutableString mutableCopy];
    
    NSLog(@"可变字符串  copy 和 mutableCopy的区别");
    NSLog(@"                  对象地址     对象指针地址   ");
    NSLog(@"mutableString: %p , %p", mutableString, &mutableString);
    NSLog(@"         copy: %p , %p", mutableStringCopy, &mutableStringCopy);
    NSLog(@"  mutalbeCopy: %p , %p", mutableStringMutableCopy, &mutableStringMutableCopy);

运行结果
运行结果
分析:
从打印结果来看,不管是copy还是mutableCopy,对象的指针地址都发生了变化,说明都会创建新的指针。

针对NSString类型来看,copy后对象地址没有变化,说明copy只是创建了新的指针,指针指向的还是原来的内存地址。mutalbeCopy之后对象地址也发生了变化,说明mutalbeCopy创建了新的指针,同时开辟了新的内存并将string的内容复制了过去。

针对NSMutableString类型来看,不论是copy还是mutalbeCopy,对象的指针地址和对象地址都发生了变化,因此两种形式都开辟了新内存并将内容复制到的新内存中。

PS:
1、使用NSMutableString类型接收NSString类型copymutableCopy之后的值,然后进行appendString,结果发现copy之后的对象不能进行appendString,会发生闪退。
2、使用NSMutableString类型接收NSMutableString类型copymutableCopy之后的值,然后进行appendString,结果同样发现copy之后的对象不能进行appendString,会发生闪退。

3、结论

1、对于不可变类型NSString来说,copy是浅拷贝,mutableCopy是深拷贝,同时mutableCopy之后变成了NSMutableString类型。
2、对于可变类型NSMutableString来说,copymutableCopy都是深拷贝,都进行了内容拷贝,但是copy之后数据类型变成了NSString类型。
3、copy之后结果是不可变类型,不能直接操作值的改变。mutableCopy之后结果都是可变数据类型。

NSArray 和 NSMutableArray

1、概述

按照上面NSStringNSMutableString系统非集合类对象的思路,对NSArrayNSMutableArray系统集合类对象做同样的示例分析。

因为集合类对象里面的元素还可以是对象,因此需要打印内部元素的地址信息,查看是否进行了深拷贝。

2、示例分析
	NSArray *cellArray1 = @[@"1", @"2", @"3"];
    NSArray *cellArray2 = @[@"4", @"5", @"6"];
    
    NSArray *array = @[cellArray1, cellArray2];
    NSArray *arrayCopy = [array copy];
    NSArray *arrayMutableCopy = [array mutableCopy];
        
    NSArray *tempArray = array.firstObject;
    NSArray *tempArrayCopy = arrayCopy.firstObject;
    NSArray *tempArrayMutableCopy = arrayMutableCopy.firstObject;
    
    NSLog(@"不可变数组  copy 和 mutableCopy的区别");
    NSLog(@"                对象地址     对象指针地址  firstObject地址  firstObject指针地址");
    NSLog(@"      array: %p , %p , %p , %p", array, &array, tempArray, &tempArray);
    NSLog(@"       copy: %p , %p , %p , %p", arrayCopy, &arrayCopy, tempArrayCopy, &tempArrayCopy);
    NSLog(@"mutalbeCopy: %p , %p , %p , %p", arrayMutableCopy, &arrayMutableCopy, tempArrayMutableCopy, &tempArrayMutableCopy);

运行结果
运行结果

	NSMutableArray *mutableArray = [NSMutableArray arrayWithArray:@[cellArray1, cellArray2]];
    NSMutableArray *mutableArrayCopy = [mutableArray copy];
    NSMutableArray *mutableArrayMutableCopy = [mutableArray mutableCopy];
    
    NSMutableArray *tempMutableArray = mutableArray.firstObject;
    NSMutableArray *tempMutableArrayCopy = mutableArrayCopy.firstObject;
    NSMutableArray *tempMutableArrayMutableCopy = mutableArrayMutableCopy.firstObject;
    
    NSLog(@"可变数组  copy 和 mutableCopy的区别");
    NSLog(@"                 对象地址     对象指针地址  firstObject地址  firstObject指针地址");
    NSLog(@"mutableArray: %p , %p , %p , %p", mutableArray, &mutableArray, tempMutableArray, &tempMutableArray);
    NSLog(@"        copy: %p , %p , %p , %p", mutableArrayCopy, &mutableArrayCopy, tempMutableArrayCopy, &tempMutableArrayCopy);
    NSLog(@" mutalbeCopy: %p , %p , %p , %p", mutableArrayMutableCopy, &mutableArrayMutableCopy, tempMutableArrayMutableCopy, &tempMutableArrayMutableCopy);

运行结果
运行结果
分析:
1、copymutableCopy之后对象地址的变化与非集合对象变化相同。
2、无论是copy还是mutableCopy,内部元素的地址都没有变化,只是指针地址发生了变化。

3、结论

1、从打印的地址结果中可以看出,集合对象和非集合对象表现的结果相同,对于可变对象而言copy是浅拷贝,mutableCopy是深拷贝,同时mutableCopy之后变成了NSMutableArray类型。
2、对于可变类型NSMutableArray来说,copymutableCopy都是深拷贝,都进行了内容拷贝,但是copy之后数据类型变成了NSArray类型。
3、值得注意的是,即使mutableCopy做的也只是浅层深拷贝,即只在新开辟的内存中子项指针指向的还是原来的内存地址。

自定义对象的深拷贝和浅拷贝

1、概述

自定义对象的深拷贝和浅拷贝,首先自定义对象需要实现NSCopyingNSMutableCopying协议,否则系统会报错。

下面对自定义对象的深拷贝和浅拷贝方式做代码示例。

2、应用示例
自定义对象Example的实现代码
@interface Example : NSObject <NSCopying, NSMutableCopying>

@property (nonatomic, strong) NSString *exampleTitle;

@end
@implementation Example

@synthesize exampleTitle;

// 实现copyWithZone方法
- (id)copyWithZone:(NSZone *)zone {
    Example *example = [[self class] allocWithZone:zone];
    example.exampleTitle = self.exampleTitle;
    return example;
}

// 实现mutableCopyWithZone方法
- (id)mutableCopyWithZone:(NSZone *)zone {
    Example *example = [[self class] allocWithZone:zone];
    example.exampleTitle = self.exampleTitle;
    return example;
}

@end

自定义对象的copy和mutableCopy
	Example *example1 = [[Example alloc] init];
    example1.exampleTitle = @"test1";
    
    Example *exampleCopy = [example1 copy];
    Example *exampleMutableCopy = [example1 mutableCopy];
    
    NSString *title = example1.exampleTitle;
    NSString *titleCopy = exampleCopy.exampleTitle;
    NSString *titleMutableCopy = exampleMutableCopy.exampleTitle;
    
    NSLog(@"自定义对象 copy 和 mutableCopy的区别");
    NSLog(@"                对象地址     对象指针地址      属性地址     属性指针地址");
    NSLog(@"    Example: %p , %p , %p , %p", example1, &example1, title, &title);
    NSLog(@"       copy: %p , %p , %p , %p", exampleCopy, &exampleCopy, titleCopy, &titleCopy);
    NSLog(@"mutalbeCopy: %p , %p , %p , %p", exampleMutableCopy, &exampleMutableCopy, titleMutableCopy, &titleMutableCopy);

运行结果
运行结果
小结:
1、自定义对象使用copymutableCopy时,需要实现NSCopyingNSMutableCopying协议,否则代码运行时会报错。
2、自定义对象使用copymutableCopy之后,对象的地址和指针地址都发生了变化,但是属性地址还是指向原来的地址,也就是说实际也是浅层的深拷贝。
3、因为copyWithZone方法和mutableCopyWithZone都是自己重写的,所以其实自定义对象使用copy还是mutableCopy并没有什么区别。

数组中的元素是自定义对象时的深拷贝和浅拷贝

上代码

	Example *example2 = [[Example alloc] init];
    example2.exampleTitle = @"test2";
    
    NSArray *exampleArray = [[NSArray alloc] initWithObjects:example2, nil];
    NSArray *shallowCopyArray = [[NSArray alloc] initWithArray:exampleArray];
    NSArray *deepCopyArray = [[NSArray alloc] initWithArray:exampleArray copyItems:YES];
    
    Example *shallowCopyExample = shallowCopyArray.firstObject;
    Example *deepCopyExample = deepCopyArray.firstObject;
    
    example2.exampleTitle = @"where is test2";
    
    NSLog(@"数组中存在自定义对象的浅拷贝和深拷贝");
    NSLog(@"                对象地址     对象指针地址      属性地址     属性指针地址   属性值");
    NSLog(@"    exampleArray: %p , %p , %p , %p , %@", exampleArray, &exampleArray, example2, &example2, example2.exampleTitle);
    NSLog(@"shallowCopyArray: %p , %p , %p , %p , %@", shallowCopyArray, &shallowCopyArray, shallowCopyExample, &shallowCopyExample, shallowCopyExample.exampleTitle);
    NSLog(@"   deepCopyArray: %p , %p , %p , %p , %@", deepCopyArray, &deepCopyArray, deepCopyExample, &deepCopyExample, deepCopyExample.exampleTitle);

运行结果
运行结果
小结:
1、从运行结果中可以看出,使用initWithArray:方法实现的是浅拷贝,原对象的值发生改变新数组中也会同步改变。
2、使用initWithArray: copyItems:方法实现的是深拷贝,数组和数组中的对象都会开辟新的内存,因此原数组中的数据发生变化,新数组不会变化。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值