0
点赞
收藏
分享

微信扫一扫

copy修饰、浅拷贝&深拷贝 的区别

十里一走马 2021-09-29 阅读 80
日记本

在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;
}
举报

相关推荐

0 条评论