在iOS中,strong、copy均可以作为属性修饰符,二者之间区别明显;对象的拷贝过程还涉及到两个方法copy和mutableCopy,他们之间也有明显区别。
1. copy修饰符
下面对比一下属性修饰符中copy、strong的区别:
@interface ViewController ()
@property (copy, nonatomic) NSString *text1;
@property (strong, nonatomic) NSString *text2;
@end
// 源字符串为NSString
- (void)test1 {
NSString *temp = @"this is temp string";
NSLog(@"temp %p",temp); //0x10a23e0f8
self.text1 = temp;
NSLog(@"copy text1%p",self.text1);//0x10a23e0f8
self.text2 = temp;
NSLog(@"strong text2%p",self.text2);//0x10a23e0f8
}
// 源字符串为NSMutableString
- (void)test2 {
NSMutableString *temp = [[NSMutableString alloc]initWithString:@"this is tempString"];
NSLog(@"temp指向的地址%p",temp);//0x61800026a600
self.text1 = temp;
NSLog(@"copy text1指向的地址%p",self.text1);//0x608000244710
self.text2 = temp;
NSLog(@"strong text2指向的地址%p",self.text2);//0x61800026a600
[temp appendString:@" lalala--->>>"];
NSLog(@"text1 is %@ \n text2 is %@",self.text1,self.text2);//text2 is this is tempString lalala--->>>
}
可以看出属性修饰符中的copy操作,并不是我们单纯理解的拷贝一份内存空间,而是对所指向对象的copy操作;strong是对所指向对象的强引用。
2. 浅拷贝&深拷贝
- 浅拷贝
是对内存地址的复制,让目标对象指针和源对象指向同一片内存空间; - 深拷贝
是指拷贝对象的具体内容,而内存地址是自主分配的,拷贝出和原来仅仅是值一样,但是内存地址完全不一样的新的对象,创建后和原对象没有任何关系。
iOS中在容器与非容器、可变与不可变对象上使用copy与mutableCopy,所达到拷贝效果不一样:
2.1 非容器类的
- 对于不可变对象NSString
其copy是浅拷贝,且copy返回的对象是不可变对象;mutableCopy是深拷贝。
- (void)testNSString {
NSString *str1 = @"test001";
NSMutableString *str2 = [str1 copy];
//copy返回的是不可变对象,str2不能被修改,因此会发生崩溃
//[str2 appendString:@"test"];
NSMutableString *str3 = [str1 mutableCopy];
[str3 appendString:@"modify"];
NSLog(@"str1:%p - %@ \r\n",str1,str1);
NSLog(@"str2:%p - %@ \r\n",str2,str2);
NSLog(@"str3:%p - %@ \r\n",str3,str3);
}
//str1:0x106abdbd0 - test001
//str2:0x106abdbd0 - test001
//str3:0x608000260940 - test001modify
- 对于可变对象NSMutableString
其copy与mutableCopy都是深拷贝,且对于NSMutableString 的 copy 返回的对象是不可变对象。
- (void)testNSMutableString {
NSMutableString *mstr1 = [NSMutableString stringWithString:@"test002"];
NSMutableString *mstr2 = [mstr1 copy];
//copy返回的是不可变对象,报错“[NSTaggedPointerString appendString:]: unrecognized selector sent to instance 0x9fed68ab4c254a19"”
//[mstr2 appendString:@"test"];
NSMutableString *mstr3 = [mstr1 mutableCopy];
[mstr3 appendString:@"modify"];
NSLog(@"mstr1:%p - %@ \r\n",mstr1,mstr1);
NSLog(@"mstr2:%p - %@ \r\n",mstr2,mstr2);
NSLog(@"mstr3:%p - %@ \r\n",mstr3,mstr3);
}
//mstr1、mstr2、mstr3 地址都不同!
//mstr1:0x600003efe400 - test002
//mstr2:0x432a7e5c9811aa31 - test002
//mstr3:0x600003efe430 - test002modify
2.2 容器类的
- 不可变对象NSArray
其copy是浅拷贝,且copy返回的对象是不可变对象;mutableCopy是深拷贝。
- (void) testNSMutableArray {
NSArray *arry1 = [[NSArray alloc] initWithObjects:@"value1", @"value2",nil];
NSArray *arry2 = [arry1 copy];
NSArray *arry3 = [arry1 mutableCopy];
NSLog(@"arry1:%p - %@ \r\n",arry1,arry1);
NSLog(@"arry2:%p - %@ \r\n",arry2,arry2);
NSLog(@"arry3:%p - %@ \r\n",arry3,arry3);
}
//arry1:0x60800003b480 - (
// value1,
// value2
//)
//arry2:0x60800003b480 - (
// value1,
// value2
//)
//arry3:0x60800004cd20 - (
// value1,
// value2
//)
- 可变对象NSMutableArray
其copy与mutableCopy都是深拷贝,且copy返回的对象是不可变对象。
- (void) TestNSMutableArray {
NSMutableArray *marry1 = [[NSMutableArray alloc] initWithObjects:@"value1", @"value2",nil];
NSMutableArray *marry2 = [marry1 copy];
//copy返回的是不可变对象,marry2不能被修改,因此会崩溃
//[marry2 addObject:@"value3"];
NSMutableArray *marry3 = [marry1 mutableCopy];
NSLog(@"marry1:%p - %@ \r\n",marry1,marry1);
NSLog(@"marry2:%p - %@ \r\n",marry2,marry2);
NSLog(@"marry3:%p - %@ \r\n",marry3,marry3);
}
//marry1、marry2、marr3 地址都不一样
//marry1:0x600000048d60 - (
// value1,
// value2
//)
//marry2:0x600000026000 - (
// value1,
// value2
//)
//marry3:0x6000000494b0 - (
// value1,
// value2
//)
3. 复合类型对象的完全深拷贝
- 归档/解档
- (void) deplyFullCopy {
NSMutableArray *marry1 = [[NSMutableArray alloc] init];
NSMutableString *mstr1 = [[NSMutableString alloc]initWithString:@"value1"];
NSMutableString *mstr2 = [[NSMutableString alloc]initWithString:@"value2"];
[marry1 addObject:mstr1];
[marry1 addObject:mstr2];
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:marry1];
NSArray *marray2 = [NSKeyedUnarchiver unarchiveTopLevelObjectWithData:data error:nil];
NSLog(@"marry1:%p - %@ \r\n",marry1,marry1);
NSLog(@"marry2:%p - %@ \r\n",marray2,marray2);
NSLog(@"数组元素地址:value1:%p - value2:%p \r\n",marry1[0],marry1[1]);
NSLog(@"数组元素地址:value1:%p - value2:%p \r\n",marray2[0],marray2[1]);
}
- 调用NSArray的初始化方法
// - (instancetype)initWithArray:(NSArray<ObjectType> *)array copyItems:(BOOL)flag;
- (void) deplyFullCopy2 {
NSMutableArray *marry1 = [[NSMutableArray alloc] init];
NSMutableString *mstr1 = [[NSMutableString alloc]initWithString:@"value1"];
NSMutableString *mstr2 = [[NSMutableString alloc]initWithString:@"value2"];
[marry1 addObject:mstr1];
[marry1 addObject:mstr2];
NSArray *marray2 = [[NSArray alloc] initWithArray:marry1 copyItems:YES];
NSLog(@"marry1:%p - %@ \r\n",marry1,marry1);
NSLog(@"marry2:%p - %@ \r\n",marray2,marray2);
NSLog(@"数组元素地址:value1:%p - value2:%p \r\n",marry1[0],marry1[1]);
NSLog(@"数组元素地址:value1:%p - value2:%p \r\n",marray2[0],marray2[1]);
}
- 重写copy方法
让自定义对象具备copy操作需要实现协议<NSCopying,NSMutableCopying>,示例如下:
@interface MyObj : NSObject<NSCopying,NSMutableCopying> {
NSMutableString *name;
NSString *imutableStr;
int age;
}
@property (nonatomic, retain) NSMutableString *name;
@property (nonatomic, retain) NSString *imutableStr;
@property (nonatomic) int age;
@end
@implementation MyObj
@synthesize name;
@synthesize age;
@synthesize imutableStr;
- (id)init {
if (self = [super init]) {
self.name = [[NSMutableString alloc]init];
self.imutableStr = [[NSString alloc]init];
age = -1;
}
return self;
}
- (void)dealloc {
[name release];
[imutableStr release];
[super dealloc];
}
- (id)copyWithZone:(NSZone *)zone {
MyObj *copy = [[[self class] allocWithZone:zone] init];
copy->name = [name copy];
copy->imutableStr = [imutableStr copy];
// copy->name = [name copyWithZone:zone];;
// copy->imutableStr = [name copyWithZone:zone];//
copy->age = age;
return copy;
}
- (id)mutableCopyWithZone:(NSZone *)zone {
MyObj *copy = NSCopyObject(self, 0, zone);
copy->name = [self.name mutableCopy];
copy->age = age;
return copy;
}