——Java培训、Android培训、iOS培训、.Net培训——–
1)什么是copy
copy的字面意思是“复制”,“拷贝”,是一个产生副本的过程
对象copy的目的:要使用某个对象的数据,但是不会改变这个对象的内容。
常见的复制会用一个源文件产生:文件复制
作用:一个副本文件
2)特点
修改源文件或副本文件的内容,不会影响到另一个。
OC中的copy,就是指对象的拷贝
作用:利用一个源对象产生一个副本对象
3)如何使用copy功能
一个对象可以调用copy和mutableCopy方法来创建爱你一个副本对象
【copy】创建的是一个不可变副本(如NSString,NSArray,NSDictionary)
【mutableCopy】创建的使用一个可变副本
4)使用copy功能的前提
【copy】:需要遵守NSCopying协议,实现copyWithZone:方法
@protocol NSCopying
- (id)copyWithZone:(NSZone *)zone;
@end
【mutableCopy】需要遵守NSMutableCopying协议,实现mutableCopyWithZone:方法
@protocol NSMutableCopying
- (id)mutableCopyWithZone:(NSZone *)zone;
@end
copy是浅复制,没有产生新的对象。
mutable是深复制,在内存中产生了新空间,产生了新对象
例如:
//1、对于不可变对象的copy和mutableCopy
NSString *str = @"I am Amos....";
NSLog(@"str = %@,address = %p",str,str);
//1)copy产生的是不可变的对象
NSMutableString *ms1 = [str copy];
//会报错,因为动态类型检查时,str copy产生的是一个不可变的字符串,没有appendFormat方法
//[ms1 appendFormat:@"hhh"];
//NSLog(@"ms1 = %@,address = %p",ms1,ms1);
//2)mutableCopy 产生的是一个可变对象
NSMutableString *ms2 = [str mutableCopy];
//不会报错
[ms2 appendFormat:@"hhh"];
NSLog(@"str = %@, ms2 = %@,address = %p",str,ms2,ms2);
//2、对于可变对象的copy和mutableCopy
//1)copy产生的是不可变的对象
NSMutableString *ms3 = [ms2 copy];
NSLog(@"ms3 = %@,str2 = %@",ms3,ms2);
NSLog(@"\nms3 address:%p\nms2 address = %p",ms3,ms2);
//会报错:要坚定【copy产生的是不可变对象】
//[ms3 appendFormat:@"mmm"];
//不会报错,【mutableCopy产生的是可变对象】
ms3 = [ms2 mutableCopy];
[ms3 appendFormat:@"mmm"];
//3、可变对象的值深拷贝给不可变对象
[ms3 appendFormat:@"222"];
//此时产生了一个可变对象,虽然是NSString指向的,但是动态类型判断时会直到它就是个可变对象
NSString *str2 = [ms3 mutableCopy];
NSLog(@"ms3 = %@,str2 = %@",ms3,str2);
[(NSMutableString*)str2 appendFormat:@"2"];
NSLog(@"\nms3 address:%p\nstr2 address = %p",ms3,str2);
不可变对象,进行了copy【浅拷贝】以后,没有重新分配空间,但是会影响引用计数值
NSString *str = @"I am Amos....";
NSLog(@"str address = %p,retainCount = %ld",str, (unsigned long)[str retainCount]);
//1)copy是浅拷贝,没有开辟新空间,拷贝后两个指针指向原对象
//两个对象的地址相同,引用计数都为2,其实两个对象就是同一个对象
NSString *copyStr = [str copy];
NSLog(@"str address = %p,retainCount = %ld",str,(unsigned long)[str retainCount]);
NSLog(@"copyStr address = %p,retainCount = %ld",copyStr, (unsigned long)[copyStr retainCount]);
//2)mutableCopy深拷贝,开辟了一个新的空间,存储副本对象
//两个对象的地址不同,且副本对象的引用计数为1,副本与原对象不是同一个对象
NSMutableString *ms1 = [str mutableCopy];
NSLog(@"ms1 address = %p,retainCount = %ld",ms1, (unsigned long)[ms1 retainCount]);
【引入】
//定义一个Person类用于测试
#pragma mark Person类声明部分
@interface Person : NSObject
@property(nonatomic,retain) NSString *name;
@end
#pragma mark Person类实现部分
@implementation Person
//重写dealloc方法
- (void)dealloc
{
NSLog(@"人挂了...");
[super dealloc];
}
@end
int main(int argc, const char * argv[])
{
@autoreleasepool {
Person * p = [[Person alloc] init];
p.name = @"Amos";
NSLog(@"name = %@",p.name);
NSMutableString *ms = [NSMutableString string];
[ms appendFormat:@"Allen"];
NSLog(@"retainCount1 = %ld",[ms retainCount]);
//设置姓名
p.name = ms;
NSLog(@"name = %@",p.name);
NSLog(@"retainCount2 = %ld",[ms retainCount]);
//修改可变字符串ms
[ms appendFormat:@"&Andy"];
NSLog(@"name = %@",p.name);
[p release];
}
return 0;
}
【打印结果】
1)@property(nonatomic,retain) NSString *name;当成员变量使用retain时
2015-10-09 09:46:21.662 Copy关键字的作用[2063:303] name = Amos
2015-10-09 09:46:21.664 Copy关键字的作用[2063:303] retainCount1 = 1
2015-10-09 09:46:21.665 Copy关键字的作用[2063:303] name = Allen
2015-10-09 09:46:21.665 Copy关键字的作用[2063:303] retainCount2 = 2
2015-10-09 09:46:21.666 Copy关键字的作用[2063:303] name = Allen&Andy
2015-10-09 09:46:21.666 Copy关键字的作用[2063:303] 人挂了…
2)@property(nonatomic,copy) NSString *name;当成员变量使用copy时
2015-10-09 09:45:40.202 Copy关键字的作用[2040:303] name = Amos
2015-10-09 09:45:40.204 Copy关键字的作用[2040:303] retainCount1 = 1
2015-10-09 09:45:40.205 Copy关键字的作用[2040:303] name = Allen
2015-10-09 09:45:40.205 Copy关键字的作用[2040:303] retainCount2 = 1
2015-10-09 09:45:40.206 Copy关键字的作用[2040:303] name = Allen
2015-10-09 09:45:40.206 Copy关键字的作用[2040:303] 人挂了…
【分析结果】
由上述结果可知,成员变量在copy和retain两个关键字时是不同的,当使用retain关键字时,name的值还会因为原对象的改变而改变,因为retain赋值时返回的是源对象,并把计数器值+1.而copy只是拷贝了源对象的副本,源对象的改变对该成员变量以后的值并无影响
1)非ARC
A、copy:只用于NSString、block
B、retain:除了NSString、block以外的OC对象
C、assign:基本数据类型,枚举、结构体(非OC对象),当两个对象互相引用,一端用retain,一端用assign
2)ARC
A、copy: 只用于NSString、block
B、strong:除了NSString、block以外的OC对象
C、weak:当两个对象互相引用,一端用strong,一端用weak
D 、assign:基本数据类型,枚举、结构体(非OC对象)
新建Person类
为Person类实现copy操作
1)让Person类遵守NSCopying协议
2)实现copyWithZone方法,在该方法中返回一个对象的副本即可
3)在copyWithZone方法中,创建一个新的对象,并设置该对象的数据域现有对象一致,并返回该对象
创建Person对象,调用copy方法,查看地址。
1)调用copy其实就是调用copyWithZone方法,所以要实现copyWithZone方法
2)copyWithZone方法返回值类型是id类型,需要返回一个对象的副本
3)如果对象没有可变与不可变的版本区别,只要实现copyWithZone方法即可
4)copyWithZone:方法的具体实现
【Person.h文件】
@interface Person : NSObject<NSCopying>
@property(nonatomic,assign) int age;
@property(nonatomic,assign) NSString *name;
@end
【Person.m文件】
#import "Person.h"
@implementation Person
-(id)copyWithZone:(NSZone *)zone{
NSLog(@"执行copy方法");
//生成一个Person的副本,使副本与源对象之间互不影响
Person * p = [[Person alloc] init];
p.name = self.name;
p.age = self.age;
return p;
}
【main.m文件】
#import
#import "Person.h"
int main(int argc, const char * argv[])
{
@autoreleasepool {
//定义一个Person对象
Person *p = [Person new];
p.name = @"Amos";
p.age = 22;
//拷贝一个副本
Person *p2 = [p copy];
NSLog(@"\nname = %@,age = %d,address = %p",p.name,p.age,p);
p.name = @"234";
NSLog(@"\nname = %@,age = %d,adress = %p",p2.name,p2.age,p2);
}
return 0;
}
【打印结果】
2015-10-09 10:26:28.669 自定义类实现copy方法[2568:303] 执行copy方法
2015-10-09 10:26:28.671 自定义类实现copy方法[2568:303]
name = Amos,age = 22,address = 0x100108ad0
2015-10-09 10:26:28.672 自定义类实现copy方法[2568:303]
name = Amos,age = 22,adress = 0x1003007d0