Copia profunda y copia superficial en iOS

prefacio

  • 比喻El punto de vista utilizado 浅拷贝es que se crea un archivo 快捷方式y, en esencia, 快捷方式apunta al archivo original. 深拷贝es hacer real al archivo 复制粘贴, formando un nuevo archivo independiente.

  • Usando 指向内存地址el punto de vista, 浅拷贝el objeto apunta a la dirección de memoria del objeto copiado y 深拷贝el objeto apunta a una nueva dirección de memoria.

1. métodos copy y mutableCopy

Cabe señalar que no podemos considerar copysum simplemente mutableCopycomo 浅拷贝sum 深拷贝.

  • Para copy, el objeto copiado es 不可变对象浅拷贝, 可变对象深拷贝
  • para mutableCopyambos深拷贝
  • Para copy, independientemente de si el objeto copiado es mutable o no, el objeto copiado es inmutable
  • Para mutableCopy , independientemente de si el objeto copiado es mutable, el objeto copiado es mutable

Los objetos de iOS se pueden dividir aproximadamente en 容器对象y 非容器对象, subdivididos, se pueden dividir en 可变容器对象(NSMutableArray), 不可变容器对象(NSArray), 可变非容器对象(NSMutableString,NSMutableDictionary), 不可变非容器对象(NSString,NSDictionary).

Verifiquemos el efecto de copy y mutableCopy

  1. objetos inmutables no contenedores
  NSString *str1 = @"非容器不可变对象";
  NSString *str2 = [str1 copy];
  NSString *str3 = [str1 mutableCopy];
        
  NSLog(@"str1:%p class:%@",str1,[str1 class]);
  NSLog(@"str2:%p class:%@",str2,[str2 class]);
  NSLog(@"str3:%p class:%@",str3,[str3 class]);

 //  打印结果
  str1:0x105718738     class:__NSCFConstantString
  str2:0x105718738     class:__NSCFConstantString
  str3:0x60400024eb80  class:__NSCFString
  
复制代码

Conclusión: Para 非容器不可变对象, copy浅拷贝, mutableCopy深拷贝

  1. objetos mutables no contenedores
 NSMutableString *str1  = [NSMutableString stringWithFormat:@"非容器可变对象"];
 NSMutableString *str2 = [str1 copy];
 NSMutableString *str3 = [str1 mutableCopy];
        
 NSLog(@"str1:%p class:%@",str1,[str1 class]);
 NSLog(@"str2:%p class:%@",str2,[str2 class]);
 NSLog(@"str3:%p class:%@",str3,[str3 class]);
 
 // 打印结果
 str1:0x600000251be0 class:__NSCFString
 str2:0x600000251010 class:__NSCFString
 str3:0x600000251c40 class:__NSCFString
复制代码

Conclusión: Para 非容器可变对象, copy, mutableCopyambos深拷贝

这个结论其实解释了NSString对象建议用copy而不是strong关键字修饰的问题-数据安全问题。详细见下面。

  1. 容器不可变对象
NSArray *array1 = [NSArray arrayWithObjects:@"非容器不可变对象",[NSMutableString stringWithFormat:@"非容器可变对象"], nil];
NSArray *array2 = [array1 copy];
NSArray *array3 = [array1 mutableCopy];
        
NSLog(@"array:%p  copyArray:%p  mutableCopyArray:%p",array1,array2,array3);
NSLog(@"array1[0]:%p   array1[1]:%p  ",array1[0] , array1[1]);
NSLog(@"array2[0]:%p   array2[1]:%p  ",array2[0] , array2[1]);
NSLog(@"array3[0]:%p   array3[1]:%p  ",array3[0] , array3[1]);

 //  打印结果
array:0x6040002312a0  copyArray:0x6040002312a0  mutableCopyArray:0x6040002544f0
array1[0]:0x105718738   array1[1]:0x60400024eb80
array2[0]:0x105718738   array2[1]:0x60400024eb80
array3[0]:0x105718738   array3[1]:0x60400024eb80

复制代码

结论: 1. 对于容器不可变对象来说, copy浅拷贝, mutableCopy深拷贝

             2. 对于容器内的元素来说,`copy`和`mutableCopy`都是`浅拷贝` 
复制代码
  1. 容器可变对象
NSMutableArray *array1 = [NSMutableArray arrayWithObjects:@"非容器不可变对象",[NSMutableString stringWithFormat:@"非容器可变对象"], nil];
NSMutableArray *array2 = [array1 copy];
NSMutableArray *array3 = [array1 mutableCopy];
        
NSLog(@"array1:%p  array2:%p  array3:%p",array1,array2,array3);
NSLog(@"array1[0]:%p   array1[1]:%p ",array1[0], array1[1]);
NSLog(@"array2[0]:%p   array2[1]:%p ",array2[0], array2[1]);
NSLog(@"array3[0]:%p   array3[1]:%p ",array3[0], array3[1]);

// 打印结果
array1:0x604000254820  array2:0x604000231a00  array3:0x6040002545b0
array1[0]:0x105718738   array1[1]:0x6040002544f0
array2[0]:0x105718738   array2[1]:0x6040002544f0
array3[0]:0x105718738   array3[1]:0x6040002544f0

复制代码

结论:1. 对于容器可变对象来说,copy,mutableCopy都是深拷贝

2.对于容器内的元素来说,copymutableCopy都是浅拷贝

  1. copy 与mutableCopy 后得到的对象
NSString *str1 = @"非容器不可变对象";
NSMutableString *str2 = [str1 mutableCopy];
[str2 appendString:@"111"];
NSLog(@"str2:%@",str2);

// 打印结果
str2:非容器不可变对象111

/******************************************************************************/

NSMutableString *str1 = [NSMutableString stringWithFormat:@"非容器可变对象"];
NSMutableString *str2 = [str1 copy];
[str2 appendString:@"111"];

// 执行[str2 appendString:@"111"]报错
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Attempt to mutate immutable object with appendString:'
复制代码

结论:1. 不论被拷贝对象是否可变,执行了mutableCopy之后得到的对象都是可变的

2.不论被拷贝对象是否可变,执行了copy之后得到的对象都不可变

  1. 自定义对象
  • 对于copy,自定义类需要添加NSCopying协议,并实现对应的copyWithZone:方法。
  • 对于mutableCopy,自定义类需要添加NSMutableCopying协议,并实现对应的mutableCopyWithZone:方法。
@interface Singer() <NSCopying>
@property (nonatomic, strong) NSString *name;
@end

- (id)copyWithZone:(NSZone *)zone {
  
    Singer *singer = [[Singer allocWithZone:zone] init];
    singer.name = self.name; 
    return singer;
}
复制代码

二. NSString 对象copy和strong关键字修饰的区别

  • 对于不可变字符串,copystrong关键字修饰并无差别
  • 对于可变字符串:
    1. copy修饰的属性赋值时会进行一次copy操作(对于可变字符串的拷贝是深拷贝),也就是为它开辟了新的内存地址。
    2. strong 修饰的属性则不会进行深拷贝操作,不会开辟新的内存地址。
NSString *str = @"我是个不可变字符串";
self.strongStr = str;
self.copyedStr = str;
       
NSLog(@"str:%p, strongStr:%p, copyedStr:%p",str,self.strongStr,self.copyedStr);

// 打印结果
str:0x10cd90978, strongStr:0x10cd90978, copyedStr:0x10cd90978

复制代码

当字符串是不可变类型时,self.strongStrself.copyedStr 并无区别,指向的都是str 的内存地址。

NSMutableString *str = [NSMutableString stringWithFormat:@"我是个可变字符串"];
self.strongStr = str;
self.copyedStr = str;
[str appendString:@"哈哈哈"];

NSLog(@"str:%p, strongStr:%p, copyedStr:%p",str,self.strongStr,self.copyedStr);
NSLog(@"str:%@, strongStr:%@, copyedStr:%@",str,self.strongStr,self.copyedStr);

// 打印结果
str:0x6000002507d0, strongStr:0x6000002507d0, copyedStr:0x600000251760
str:我是个可变字符串哈哈哈, strongStr:我是个可变字符串哈哈哈, copyedStr:我是个可变字符串
复制代码

当字符串是可变类型时,self.copyedStr指向了新的内存地址,self.copyedStr指向的依旧是str的内存地址。

strong关键字修饰NSString类型的属性究竟会造成什么问题呢? 当我们对strongStr属性赋值完毕之后,对str进行修改,由于指向的是同一个内存地址,self. strongStr的值也发生了变化。strongStr在我们不知道的情况下发生了修改行为,这是不安全的。所以在类型不明确的情况下,一般建议使用copy关键字修饰NSString类型的属性。

Supongo que te gusta

Origin juejin.im/post/7055644634894057479
Recomendado
Clasificación