对于对象具有拷贝功能,则需实现 NSCopying 协议。
- 声明该类遵从 NSCopying 协议
@interface Animal : NSObject <NSCopying>
@property (nonatomic, readonly, copy) NSString *name;
@property (nonatomic, readonly, assign) NSInteger age;
@property (nonatomic, assign) NSString *food;
- (instancetype)initWithName:(NSString *)name age:(NSInteger)age food:(NSString *)food;
@end
- 实现 NSCopying 协议。该协议只有一个方法: - (id)copyWithZone:(NSZone *)zone;
- (instancetype)initWithName:(NSString *)name age:(NSInteger)age food:(NSString *)food
{
if (self = [super init]) {
_name = name;
_age = age;
_food = food;
}
return self;
}
- (id)copyWithZone:(NSZone *)zone
{
Animal *copy = [[[self class] allocWithZone:zone] initWithName:_name age:_age food:_food];
return copy;
}
- 但一个类中不仅仅就只有几个基本的属性吧,假如Animal 中含有一个数组,与其他 Animal 对象建立或解除朋友关系的那些方法都需要操作这个数组,那么就需要把包含朋友对象的数组也一并拷贝过来。
@property (nonatomic, strong) NSMutableArray *friends;
- (instancetype)initWithName:(NSString *)name age:(NSInteger)age food:(NSString *)food
{
if (self = [super init]) {
_name = name;
_age = age;
_food = food;
_friends = [[NSMutableArray alloc] init];
}
return self;
}
- (id)copyWithZone:(NSZone *)zone
{
Animal *copy = [[[self class] allocWithZone:zone] initWithName:_name age:_age food:_food];
copy.friends = [_friends mutableCopy];
return copy;
}
- (void)addFriend:(Animal *)animal
{
[_friends addObject:animal];
}
- (void)removeFriend:(Animal *)animal
{
[_friends removeObject:animal];
}
- 写代码验证下:
Animal *dog = [[Animal alloc] initWithName:@"哈士奇" age:3 food:@"骨头"];
NSLog(@"dog 地址 %p", dog);
NSLog(@"dog.name %@ -- 地址 %p",dog.name, dog.name);
Animal *dog11 = [dog copy];
NSLog(@"dog11 地址 %p", dog11);
NSLog(@"dog11.name %@ -- 地址 %p",dog11.name, dog11.name);
运行结果
2018-08-27 16:48:28 [2384:424494] dog 地址 0x6000002413b0
2018-08-27 16:48:28 [2384:424494] dog.name 哈士奇 -- 地址 0x10319d0b0
2018-08-27 16:48:31 [2384:424494] dog11 地址 0x600000241680
2018-08-27 16:48:31 [2384:424494] dog11.name 哈士奇 -- 地址 0x10319d0b0
(lldb) po dog.friends
<__NSArrayM 0x60400025b4e0>(
<Animal: 0x60400025b600>,
<Animal: 0x60400025b5a0>
)
(lldb) po dog11.friends
<__NSArrayM 0x60000024b5e0>(
<Animal: 0x60400025b600>,
<Animal: 0x60400025b5a0>
)
可以看到,dog和dog11的地址是不同的,成功copy。数组friends中的元素也被copy了。 但还是有缺陷, 因为打印的结果 name和friends中元素的值一样但是地址不一样。可以得出 copy是浅拷贝 只是拷贝了 指针,并没有对内容进行拷贝。如果不要求内容拷贝, 以上便能满足对象copy功能的基本需求。
- 存放朋友对象的 friends 是用 “copyWithZone:” 方法来拷贝的,这种浅拷贝方式不会逐个复制 friends 中的元素。若需要深拷贝的话,则需要编写一个专供深拷贝所用的方法。
- (id)deepCopy
{
Animal *copy = [[[self class] alloc] initWithName:_name age:_age food:_food];
copy.friends = [[NSMutableArray alloc] initWithArray:_friends copyItems:YES];
return copy;
}
继续代码验证:
Animal *dog12 = [dog deepCopy];
NSLog(@"dog12 地址 %p", dog12);
NSLog(@"dog12.name %@ -- 地址 %p", dog12.name);
运行结果:
2018-08-27 20:59:22 [4423:610720] dog12 地址 0x60400025b450
2018-08-27 20:59:22 ObjectCopy[1888:367803] dog12.name 地址 0x10831e380
(lldb) po dog12.friends
<__NSArrayM 0x60000024b8b0>(
<Animal: 0x60400025b750>,
<Animal: 0x60000024ba00>
)
可以看出对象dog12的name地址和dog的name地址不一样, friends中的元素也被一一复制了,这样对象copy功能就完成了。
网友评论