1.简单复制只能实现浅拷贝:指针赋值,使两个指针指向相同的一块内存空间,操作不安全。
2. Foundation类已经遵守了<NSCopying>和 <NSMutableCopying>协议,即实现了copy和mutableCopy方法,因此Foundation对象可以使用这些方法创建对象的副本或可变副本
@protocol NSCopying
- (id)copyWithZone:(NSZone *)zone;
@end
@protocol NSMutableCopying
- (id)mutableCopyWithZone:(NSZone *)zone;
@end
3.用户自定义类遵守<NSCopying>协议和<NSMutableCopying>协议,则必须实现copyWithZone方法和mutableCopyWithZone方法,否则该类对象无法响应copy和mutableCopy消息
4.实现copyWithZone方法,例:
-(id)copyWithZone:(NSZone *)zone
{
Student *stu = [[Student allocWithZone:zone]initWithName:self.name Age:self.age];
return stu;
}
对应main函数中:假设已经有一个Student对象stu1;
则:Student stu2 = [stu1 copy];
实现stu2是stu1的副本,这里是深复制,stu1和stu2分别对应不同内存。
5. 如果你的类产生了子类,那么copyWithZone:方法也将
被继承
Student *stu = [[Student allocWithZone: zone] init];
该方法应该改为: Student *stu = [[[self class] allocWithZone: zone]init];
如果编写一个类的copyWithZone:方法那么子类的方法应该先调用父类的copy方法以复制继承来的copy实例变量.
1 NSCopying与NSMutableCopying协议
用copy方法能得到字符串的不可变副本,而mutableCopy方法能得到字符串的可变副本。但是如果对自定义的类,我们不能直接使用copy和mutableCopy方法,需要让类遵守NSCopying与NSMutableCopying协议,然后实现继承自协议的copyWithZone:方法和mutableCopyWithZone:方法,这两个方法返回的是对象本身,得到一个对象的副本。
总之,为了保证一个自定义的类的对象使用copy方法产生一个不可变的副本,需要做两步:
1. 让该类继承NSCopying协议。
2. 在类的代码实现部分重写继承自NSCopying协议的CopyWithZone:方法,该方法返回一个该类的不可变对象副本。
为了保证一个自定义的类的对象使用mutableCopy方法产生一个可变的副本,需要做两步:
1. 让该类继承NSMutableCopying协议。
2. 在类的代码实现部分重写继承自NSMutableCopying协议的mutableCopyWithZone:方法,该方法返回一个该类的可变对象副本。
2 深复制和浅复制
代码示例如下:GKHUser.h
[code]#import <Foundation/Foundation.h>//继承NSCopying和NSMutableCopying协议 @interface GKHUser : NSObject <NSCopying, NSMutableCopying> @property (nonatomic, strong) NSMutableString *name;//类似retain类型,引用计数 @property (nonatomic, assign) int age; @end
GKHUser.m
[code]#import "GKHUser.h"@implementation GKHUser//重写copyWithZone:方法 - (id) copyWithZone:(NSZone *)zone {NSLog(@"执行copyWithZone:方法");//使用zone参数创建一个GKHUser对象GKHUser *user = [[[self class] allocWithZone:zone] init];user.name = self.name;//这里只是浅复制user.age = self.age;return user; }//重写mutableCopyWithZone:方法 - (id) mutableCopyWithZone:(NSZone *)zone {NSLog(@"执行mutableCopyWithZone:方法");//使用zone参数创建一个GKHUser对象GKHUser *user = [[[self class] allocWithZone:zone] init];user.name = self.name;//这里只是浅复制user.age = self.age;return user; } @end
main.m
[code]#import <Foundation/Foundation.h> #import "GKHUser.h"int main(int argc, const char * argv[]) {@autoreleasepool {GKHUser *user1 = [GKHUser new];user1.name = [NSMutableString stringWithString:@"李太"];user1.age = 10;GKHUser *user2 = [user1 copy];//复制不可变副本[user1.name appendString:@"白"];user2.age = 20;NSLog(@"user1的名字为:%@", user1.name);NSLog(@"user1的年龄为:%d", user1.age);NSLog(@"user2的名字为:%@", user2.name);NSLog(@"user2的年龄为:%d", user2.age);GKHUser *user3 = [GKHUser new];user3.name = [NSMutableString stringWithString:@"张大"];user3.age = 30;GKHUser *user4 = [user3 mutableCopy];//复制可变副本[user3.name appendString:@"彪"];user4.age = 40;NSLog(@"user3的名字为:%@", user3.name);NSLog(@"user3的年龄为:%d", user3.age);NSLog(@"user4的名字为:%@", user4.name);NSLog(@"user4的年龄为:%d", user4.age);}return 0; }
运行main.m结果:
执行copyWithZone:方法
user1的名字为:李太白
user1的年龄为:10
user2的名字为:李太白
user2的年龄为:20
执行mutableCopyWithZone:方法
user3的名字为:张大彪
user3的年龄为:30
user4的名字为:张大彪
user4的年龄为:40
我们从结果中发现,不管是可变复制还是不可变复制,最后修改副本的name属性时候,会导致原始对象的属性也发生修改,为什么呢?因为这里的copyWithZone:和mutableWithZone:方法中对name属性的赋值是浅复制,如下图:
为了达到我们的效果,GKHUser.h和main.m代码不变,而GKHUser.m修改如下:
GKHUser.m
[code]#import "GKHUser.h"@implementation GKHUser//重写copyWithZone:方法 - (id) copyWithZone:(NSZone *)zone {NSLog(@"执行copyWithZone:方法");//使用zone参数创建一个GKHUser对象GKHUser *user = [[[self class] allocWithZone:zone] init];user.name = [self.name copy];//这里对name指向的对象执行深复制,复制的副本为不可变的字符串user.age = self.age;return user; }//重写mutableCopyWithZone:方法 - (id) mutableCopyWithZone:(NSZone *)zone {NSLog(@"执行mutableCopyWithZone:方法");//使用zone参数创建一个GKHUser对象GKHUser *user = [[[self class] allocWithZone:zone] init];user.name = [self.name mutableCopy];//这里对name指向的对象执行深复制,复制的副本为可变的字符串user.age = self.age;return user; } @end
运行main.m结果:
执行copyWithZone:方法
user1的名字为:李太白
user1的年龄为:10
user2的名字为:李太
user2的年龄为:20
执行mutableCopyWithZone:方法
user3的名字为:张大彪
user3的年龄为:30
user4的名字为:张大
user4的年龄为:40
这样就达到了我们的目的,user2是user1的不可变副本,实现了copy方法,而user4是user3的可变副本,实现了mutableCopy方法。
其在内存中的示意图如下: