1、拷贝的目的:
- 产生一个副本对象,跟源对象互不影响
- 修改了源对象,副本对象没有任何影响
- 修改副本对象,源对象没有任何影响
在iOS中,最常用的对象,比如:NSString、NSArray、NSDictionary、NSData、NSSet
都具有copy
功能。
iOS提供了两个拷贝方法:
- copy:不可变拷贝,产生不可变副本
- mutableCopy:可变拷贝,产生可变副本
2、深拷贝、浅拷贝
- 深拷贝:内容拷贝,有产生新对象
- 浅拷贝:指针拷贝,没有产生新对象
我们对一个NSString
进行copy
和mutableCopy
NSString *str = @"test";
NSString *str1 = [str copy];
NSMutableString *str2 = [str mutableCopy];
NSLog(@"str=%@, str1=%@, str2=%@", str, str1, str2);
NSLog(@"str=%p, str1=%p, str2=%p", str, str1, str2);
上述代码控制台输出结果如下:
str=test, str1=test, str2=test
str=0x100001040, str1=0x100001040, str2=0x10062a900
从上面的输出结果可以看出,通过copy
和mutableCopy
都能够获取到str
字符串的值,但是从内存地址可以看出,通过copy
出来的内存地址和源对象相同,通过mutableCopy
出来的内存地址和源对象不同。我们把内存地址发生改变的copy
操作叫做深拷贝,又称内容拷贝;反之,内存地址没有发生的copy
操作叫做浅拷贝,又称指针拷贝。
我们再对一个NSMutableString
进行copy
和mutableCopy
NSMutableString *str =[[NSMutableString alloc] initWithString:@"test"];
NSString *str1 = [str copy];
NSMutableString *str2 = [str mutableCopy];
NSLog(@"str=%@, str1=%@, str2=%@", str, str1, str2);
NSLog(@"str=%p, str1=%p, str2=%p", str, str1, str2);
上述代码控制台输出结果如下:
str=test, str1=test, str2=test
str=0x100459f50, str1=0x7473657445, str2=0x100459fa0
从上面的输出结果可以看出,通过copy
和mutableCopy
都能够获取到str
字符串的值,但是从内存地址可以看出,通过copy
和mutableCopy
出来的内存地址和源对象不同。所以可变字符串拷贝出来的对象都是深拷贝
从上面的两个代码实例可以看出:
- 对于不可变字符串,通过
copy
操作出的对象仅仅是浅拷贝,即指针拷贝;通过mutableCopy
操作出的对象是深拷贝,即内容拷贝- 对于可变字符串,不论是
copy
还是mutableCopy
操作出来的对象,都是深拷贝,即内容拷贝
对于NSArray、NSDictionary、NSData、NSSet
使用copy
和mutableCopy
,跟NSString
没有太大区别。
3、自定义对象实现copy
创建一个JKPerson对象,继承于NSObject
// JKPerson.h文件
#import <Foundation/Foundation.h>
@interface JKPerson : NSObject
@property (nonatomic, copy) NSString *name;
@property (nonatomic, assign) int age;
@end
// ViewController.m
JKPerson *person = [[JKPerson alloc] init];
person.name = @"Jack";
person.age = 19;
JKPerson *person1 = [person copy];
JKPerson.m
文件什么都没实现
运行程序会发现崩溃了
我们会发现
JKPerson
类找不到copyWithZone:
方法,所以对于自定义copy我们得重写copyWithZone:
方法,但是要这个类遵循NSCopying
协议修改后代码如下
// JKPerson.h文件
@interface JKPerson : NSObject <NSCopying>
@property (nonatomic, copy) NSString *name;
@property (nonatomic, assign) int age;
@end
// JKPerson.m
@implementation JKPerson
- (id)copyWithZone:(NSZone *)zone {
JKPerson *person = [[JKPerson allocWithZone:zone] init];
person.name = self.name;
person.age = self.age;
return person;
}
- (NSString *)description {
return [NSString stringWithFormat:@"name = %@, age = %d", self.name, self.age];
}
@end
// ViewController.m
JKPerson *person = [[JKPerson alloc] init];
person.name = @"Jack";
person.age = 19;
JKPerson *person1 = [person copy];
NSLog(@"perosn : %@, person1 : %@", person, person1);
NSLog(@"perosn : %p, person1 : %p", person, person1);
控制台输出结果如下图
从上图输出结果可以看出,person
成功的将name
和age
属性copy到person1
上。