1. 深拷贝和浅拷贝
a. 浅拷贝:假设A、B两个人是一家人,居住在同一个家,那么A的家庭地址与B的家庭地址必然一样。替换一下概念,把A、B看成引用对象,它们指向了同一个内存地址。则A可以看做是B的浅拷贝。对于浅拷贝而言,存在一种相互作用的关系。当对B进行操作时,那么A也会受到影响,因为它们指向的是相同的内存地址。
b. 深拷贝:假设A、B两个人不是一家人,但是它们所居住的家一模一样。这时候,虽然它们的家是一模一样的,但是A的家庭地址与B的家庭地址必然是不一样的。同样把A、B看出引用对象那个,它们指向了不同的内存地址,而且这两个内存地址里面的内容是一模一样的。则A可以看做是B的深拷贝。对于深拷贝而言,不存在任何关系。当对B进行操作时,A不会受到任何影响,虽然初始时它们的内容是一模一样的。
2.浅拷贝的弊端
浅拷贝可能会破坏面向对象编程的封装性。
# order.h
@interface Order : NSObject
@property (nonatomic, strong) NSString *remark;
@end
# main.m
Order *order = [Order new];
NSMutableString *remark = [NSMutableString stringWithString:@"我要吃鱼"];
order.remark = remark;
NSLog(@"1. order.remark=%@", order.remark);
// 对remark进行修改就会影响到order.remark的属性值
[remark appendString:@"和肉"];
NSLog(@"2. order.remark=%@", order.remark);
Log输出:
1. order.remark=我要吃鱼
2. order.remark=我要吃鱼和肉
在上面的Demo中,order对象的remark属性和remark变量存在浅拷贝的关系!这样就会导致对remark变量修改,会影响到order对象的remark属性值。这样的行为严重破坏了面向对象编程的封装性,也会让整个项目工程埋下隐患!所以,在开发时,一定要谨慎使用浅拷贝。
3. 怎么使用深拷贝
a. 对不可变属性,需要使用copy来修饰,进行深拷贝赋值。
- NSString、NSArray,NSDictionary建议使用copy修饰
- block建议使用copy修饰
b. 对自定义对象使用copy方法时,需要先重写copyWithZone方法。
# Order.h
@interface Order : NSObject <NSCopying>
@property (nonatomic, strong) NSString *remark;
@end
# Order.m
@implementation Order
- (instancetype)copyWithZone:(NSZone *)zone {
Order *copyModel = [[Order allocWithZone:zone] init];
copyModel.remark = self.remark;
return copyModel;
}
@end
c. 对可变属性,不建议使用copy修饰。
# order.h
@interface Order : NSObject
@property (nonatomic, copy) NSMutableString *remark;
@end
# main.h
Order *order = [Order new];
NSMutableString *remark = [NSMutableString stringWithString:@"我要吃鱼"];
order.remark = remark;
[order.remark appendString:@"和肉"];
错误提示:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Attempt to mutate immutable object with appendString:'
因为使用copy修饰,导致对可变对象赋值时,会进行深拷贝赋值。但是,copy方法生成的深拷贝对象是一个不可变对象,这样不可变对象就会赋值给一个可变属性。当使用到只有可变属性才具备的方法时,比如appendString方法,编译器就会报错了。
网友评论