NSCopying与NSMutableCopy协议
怎么让我们自己定义的类可以调用copy或mutableCopy来复制一个对象的副本呢?
- 1 定义一个User对象
@interface User : NSObject
@property (nonatomic ,strong) NSMutableString *name;
@property (nonatomic ,assign) int age;
@end
- (void)viewDidLoad {
[super viewDidLoad];
User *user1 = [[User alloc] init];
user1.name = @"张三";
user1.age = 20;
User *user2 = [user1 copy];
// User *user2 = [user1 mutableCopy];
NSLog(@"%@",user2.name);
}
运行
错误提示找不到 copyWithZone
方法,打开注释部分代码User *user2 = [user1 mutableCopy];
再次运行
错误提示找不到 mutableCopyWithZone
方法
由上面的举例我们可以看出要想一个类可以copy一个不变类我们需要做
- 1 遵循NSCopying协议
- 2 重写copyWithZone方法
使用mutableCopy复制一个可变的副本需要
- 1 遵循NSMutableCopy协议
2 重写mutableCopyWithZone方法
当我们调用对象的copy方法时,实质上是底层调用copyWithZone方法返回一个不可变的副本,当我们调用mutableCopy方法时,会调用mutableCopyWithZone方法返回一个可变的副本,从上面的示例可以看出如果希望我们自己的类来调用copy或mutableCopy方法必需实现copyWithZone或mutableCopyWithZone方法
为了我们自己的类可以调用copy方法我们实现copyWithZone方法
#import "User.h"
@implementation User
- (id)copyWithZone:(NSZone *)zone {
User *user = [[[self class] allocWithZone:zone] init];
user.name = self.name;
user.age = self.age;
return user;
}
@end
- (void)viewDidLoad {
[super viewDidLoad];
User *user1 = [[User alloc] init];
user1.name = [NSMutableString stringWithFormat:@"张三" ];
user1.age = 20;
User *user2 = [user1 copy];
user2.name = [NSMutableString stringWithFormat:@"李四" ];;
NSLog(@"user1%@",user1.name);
NSLog(@"user2%@",user2.name);
// Do any additional setup after loading the view, typically from a nib.
}
运行打印结果
没有问题
如果把user2.name = [NSMutableString stringWithFormat:@"李四" ]
换成[user2.name replaceCharactersInRange:NSMakeRange(0, 2) withString:@"李四"];
运行结果会是怎样的呢?
运行一下结果如下图
问题来了,我们只是改变了user2的name为什么user1的name也跟着改变了呢?
回过头来我们看一下copyWithZone
的实现User *user = [[[self class] allocWithZone:zone] init];
user.name = self.name;
user.age = self.age;
return user;
user对象name指针指向了self.name指针指向的内容,他们实质上指向内存中同一块地址,所以当我们改变user1,user2任意对象的name时两个对象的name都会改变,这种方式的copy就是浅copy,浅copy是指当对象的实例变量是指针变量时,如果只是复制该指针的地址,而不是复制指针指向的对象
从上面的示例来看,浅复制,在内存中复制了两个对象但这两个变量的指针变量指向同一个对象,也就是说这两个对象依然有公共的部分
深复制
- (id)copyWithZone:(NSZone *)zone {
User *user = [[[self class] allocWithZone:zone] init];
user.name = [self.name mutableCopy];
user.age = self.age ;
return user;
}
user对象name属性是通过[self.name mutableCopy]
方法赋值的mutableCopy是复制一个可变对象然后赋值给user.name,保证了user.name和self.name在内存中指向不同的区域,这样user1和user之间在内存中没有共同的区域,这样就实现了深复制
实现深复制之后再次编译代码运行结果如下
总结
当对象的实例变量是指针变量时,如果只是复制了该对象实例变量的指针地址,而不是复制指针指向的内容时,这种方式的复制被称为浅copy,深copy不仅会复制对象本身,而且会复制指针类型的实例变量,Foundation框架中的大部分类都只实现了浅复制