概念:
浅拷贝是指针拷贝,新指针和旧指针指向同一块地址。
深拷贝将对象也进拷贝了一份到新的内存地址,新指针指向了新内存地址。
但iOS中的深浅拷贝还分多种情况。
一、容器类对象(Array、Dictionary、Set)和非容器类对象(String)。
二、可变对象(NSArray、NSMutableDictionary、NSMutableSet、NSMutableString)和不可变对象(NSArray、NSDictionary、NSSet、NSString)。
//本文中容器类对象只用Array举例,其余同理
一、非容器类对象(以NSString和NSMutableString为例)
1.1 不可变非容器类对象:NSString
NSString* string =@"123";
NSString* copyString = [string copy];
NSString* mutCopyString = [string mutableCopy];
NSLog(@"string: %@ %p", string, string);
NSLog(@"copyString: %@ %p", copyString, copyString);
NSLog(@"mutCopyString: %@ %p", mutCopyString, mutCopyString);
【不可变】【非容器类对象】深浅拷贝打印结果
- 不可变非容器类对象:
copy->地址不变、指针复制
mutCopy->地址改变、对象复制
- 不可变非容器对象copy返回类型和原对象相同,mutCopy返回类型为__NSCFString
NSString * string = @"123";
NSString * formatString = [NSString stringWithFormat:@"123"];
不可变非容器深浅拷贝返回的对象类型
1.2 可变非容器类对象:NSMutableString
NSMutableString * mutString = [NSMutableString stringWithString:@"123"];
NSString* copyString = [mutString copy];
NSMutableString* mutCopyString = [mutString mutableCopy];
NSLog(@"mutString: %@ %p", mutString, mutString);
NSLog(@"copyString: %@ %p", copyString, copyString);
NSLog(@"mutCopyString: %@ %p", mutCopyString, mutCopyString);
NSLog(@"----------append------------");
[mutString appendString:@"9"]; //修改原字符串
NSLog(@"mutString: %@ %p", mutString, mutString);
NSLog(@"copyString: %@ %p", copyString, copyString);
NSLog(@"mutCopyString: %@ %p", mutCopyString, mutCopyString);
【可变】【非容器类对象】深浅拷贝打印结果
- 可变非容器类对象:
copy->地址改变、对象复制
mutCopy->地址改变、对象复制
修改原对象不会影响深浅拷贝后的对象。 - 不可变非容器对象copy返回类型NSTaggedPointerString,mutCopy返回类型为__NSCFString 可变非容器深浅拷贝返回的对象类型
二、容器类对象(以NSArray和NSMutableArray为例)
2.1 不可变容器类对象:NSArray
NSArray * array = @[[NSMutableString stringWithFormat:@"1"], @"2"];
NSArray * copyArray = [array copy];
NSArray * mutCopyArray = [array mutableCopy];
NSLog(@"array: %p", array);
NSLog(@"copyArray: %p", copyArray);
NSLog(@"mutCopyArray: %p", mutCopyArray);
【不可变】【容器类对象】深浅拷贝打印结果
我们来改变一个容器中的元素。
NSArray * array = @[[NSMutableString stringWithFormat:@"1"], @"2"];
NSArray * copyArray = [array copy];
NSArray * mutCopyArray = [array mutableCopy];
NSLog(@"array: %@", array);
NSLog(@"copyArray: %@", copyArray);
NSLog(@"mutCopyArray: %@", mutCopyArray);
NSLog(@"----------change------------");
NSMutableString * mutString = array[0];
[mutString appendString:@"9"]; //修改第一个元素
NSLog(@"array:%@", array);
NSLog(@"copyArray:%@ ", copyArray);
NSLog(@"mutCopyArray:%@", mutCopyArray);
【不可变】【容器类对象】深浅拷贝改变元素
对比两张打印结果图可发现,深拷贝虽然地址改变,但修改原数组会影响深拷贝后的新数组。我猜想可能是数组为对象拷贝(地址改变),但数组元素仍旧是指针拷贝。我们打印一下元素地址证实下:
NSArray * array = @[[NSMutableString stringWithFormat:@"1"], @"2"];
NSArray * copyArray = [array copy];
NSArray * mutCopyArray = [array mutableCopy];
NSLog(@"array: %p [0]%p [1]%p", array, array[0], array[1]);
NSLog(@"copyArray: %p [0]%p [1]%p", copyArray, copyArray[0], copyArray[1]);
NSLog(@"mutCopyArray: %p [0]%p [1]%p", mutCopyArray, mutCopyArray[0], mutCopyArray[1]);
【不可变】【容器类对象】深浅拷贝元素地址打印
-
不可变容器类对象:
copy->对象地址不改变(数组为指针拷贝)、元素值跟随原数组修改(元素也为指针拷贝)
mutCopy->对象地址改变(数组为对象拷贝)、元素值跟随原数组修改(元素为指针拷贝) - 且要注意,copy返回的是不可变类型,mutCopy返回的是可变类型。 不可变容器深浅拷贝返回的对象类型
2.2 可变容器类对象:NSMutableArray
NSMutableArray * mutArray = [NSMutableArray arrayWithArray:@[[NSMutableString stringWithFormat:@"1"], @"2"]];
NSArray * copyArray = [mutArray copy];
NSArray * mutCopyArray = [mutArray mutableCopy];
NSLog(@"array: %p", mutArray);
NSLog(@"copyArray: %p", copyArray);
NSLog(@"mutCopyArray: %p", mutCopyArray);
【可变】【容器类对象】深浅拷贝元素地址打印
我们再修改一个元素。
NSMutableArray * mutArray = [NSMutableArray arrayWithArray:@[[NSMutableString stringWithFormat:@"1"], @"2"]];
NSArray * copyArray = [mutArray copy];
NSArray * mutCopyArray = [mutArray mutableCopy];
NSLog(@"array: %@", mutArray);
NSLog(@"copyArray: %@", copyArray);
NSLog(@"mutCopyArray: %@", mutCopyArray);
NSLog(@"----------change------------");
[mutArray[0] appendString:@"9"];//修改数组元素
NSLog(@"array:%@", mutArray);
NSLog(@"copyArray:%@", copyArray);
NSLog(@"mutCopyArray:%@", mutCopyArray);
NSLog(@"----------change2------------");
mutArray[0] = @"0"; //直接改变元素对象
NSLog(@"array:%@", mutArray);
NSLog(@"copyArray:%@", copyArray);
NSLog(@"mutCopyArray:%@", mutCopyArray);
【可变】【容器类对象】深浅拷贝改变元素
可以看出,可变容器类对象无论是copy还是mutCopy都是深拷贝,但元素是指针拷贝。改变原数组元素的值还是会影响拷贝后的数组。但如果给原数组的元素赋值新对象,则不会影响。
可变容器深浅拷贝返回的对象类型
- 和不可变容器类对象相同,copy返回的是不可变类型,mutCopy返回的是可变类型。
总结:
对于不可变类型(无论容器类非容器类),copy是浅拷贝,mutCopy是深拷贝。
对于可变类型(无论容器类非容器类),copy和mutCopy都是深拷贝。但对于容器类对象(Array、Dictionary、Set)来说,无论深拷贝还是浅拷贝,其元素都是指针拷贝。
如何实现深拷贝(来源:深拷贝、浅拷贝)
实现深拷贝需要遵守NSCoying协议,实现- (id)copyWithZone:(NSZone *)zone方法。当对一个property属性含有copy修饰符的时候,在进行赋值操作的时候实际上就是调用这个方法。
- 父类实现深拷贝时,子类如何实现深度拷贝?
父类实现深拷贝之后,子类只要重写copyWithZone方法,在方法内部调用父类的copyWithZone方法,之后实现自己的属性的处理
- 父类没有实现深拷贝时,子类如何实现深度拷贝?
子类除了需要对自己的属性进行处理,还要对父类的属性进行处理。
网友评论