copy和mutableCopy

by admin on 2019年9月12日

这里主要有两个概念深拷贝和浅拷贝,主要涉及两个方法
- copy;- mutableCopy; 和一个属性修饰关键字@copy。

前言

捡起N久之前的知识整理一下

copy和mutableCopy

  • copy
    • 只会产生不可变的副本对象(比如NSString)
  • mutableCopy
    • 只会产生可变的副本对象(比如NSMutableString)
  • copy和mutableCopy来自NSObject,适用于所有的对象

研究下 除了对不可变的对象的不可变copy 是浅拷贝, 其余都是深拷贝

深拷贝
:即内容拷贝,指拷贝对象的具体内容,而内存地址是重新分配的,两个对象虽然存的值是相同的,但是内存地址不一样,两个对象也互不影响,互不干涉(对于集合类这里有点特殊,下面会详细讲述)。

奥门威尼斯网址,首先我们要先明白一个概念,什么是浅复制,单层深复制,完全复制(每一层都深复制)
  • 浅复制也就是所说的指针复制,并没有进行对象复制

  • 单层深复制,也就是我们经常说的深复制,我这里说的单层深复制是对于集合类所说的(即NSArray,NSDictionary,NSSet),单层深复制指的是只复制了该集合类的最外层,里边的元素没有复制,(即这两个集合类的地址不一样,但是两个集合里所存储的元素的地址是一样的)

  • 完全复制,指的是完全复制整个集合类,也就是说两个集合地址不一样,里边所存储的元素地址也不一样

1.拷贝语法的目的

改变副本的时候,不会影响到源对象
深拷贝:内容拷贝,会产生新的对象。新对象计数器置为1,源对象计数器不变。
浅拷贝:指针拷贝,不会产生新的对象。源对象计数器+1。

copy和mutableCopy拷贝系统对象

源对象类型 拷贝方法 副本对象类型 是否产生了新对象 拷贝类型
NS* copy NS* 浅拷贝
NS* mutableCopy NSMutable* 深拷贝
NSMutable* copy NS* 深拷贝
NSMutable* mutableCopy NSMutable* 深拷贝
  • 注:*是通配符,比如NSString,NSMutableString,NSArray,NSMutableArray,
    NSDictionary,NSMutableDictionary
  • 注:深拷贝 == 内容拷贝;浅拷贝 == 指针拷贝;

可变对象的 copy 和 mutableCopy

奥门威尼斯网址 1

Paste_Image.png

内存地址都不一样

浅拷贝:即指针拷贝,是对内存地址的复制,让目标对象指针和源对象指向同一片内存空间。

明白了这三个概念之后,我们就来说一下他们的区别所在:
  • 非集合类(NSString,NSNumber)

 [immutableObject copy]  //浅复制  
 [immutableObject mutableCopy] //深复制
 [mutableObject copy] //深复制
 [mutableObject mutableCopy] //深复制

结论:不可变进行copy是浅复制,mutableCopy是深复制,可变的copy,mutableCopy都是深复制

  • 集合类(NSArray,NSDictionary, NSSet)

 [immutableObject copy]  //浅复制
 [immutableObject mutableCopy] //单层深复制
 [mutableObject copy] //单层深复制
 [mutableObject mutableCopy] //单层深复制

结论:不可变进行copy是浅复制,mutableCopy是单层深复制,可变的copy,mutableCopy都是单层深复制

2.深拷贝or浅拷贝

拷贝一个object也就是创建一个新的实例,并且初始化为拷贝源的值。对于像boolean,integer这类值,拷贝就是直接赋值。对于指针形的object就分为浅拷贝和深拷贝。浅拷贝是只创建一个新的指针,并指向同一块数据。深拷贝就是数据和指针都创建。

copy拷贝自定义对象

  • 首先自定义对象需要遵守协议<NSCopying>
  • 需要重写方法-(id)copyWithZone:(NSZone *)zone,返回自定义的对象
  • [person copy];copy方法内部会调用-(id)copyWithZone:(NSZone *)zone
  • copy方法拷贝的自定义对象是可变的

-(id)copyWithZone:(NSZone *)zone
{
    // zone是系统已经分配好的内存空间
    ZMJPerson *person = [ZMJPerson allocWithZone:zone] init];
    person.age = self.age;
    person.money = self.money;
    return person;
}

不可变对象的copy 和 mutableCopy

奥门威尼斯网址 2

Paste_Image.png

不可变对象的不可变copy
内存地址是一样的.可以得出除了对不可变对象的不可变copy是浅拷贝其余都是深拷贝是正确的

补充几点:
(1)浅拷贝是拷贝对象指针,地址一样, 被copy对象销毁,copy对象无效
(2)深拷贝是拷贝指针内容,地址不同,被copy对象销毁,copy对象依旧存在
(3)集合对象的内容复制仅限于对象本身,对象元素仍然是指针复制,如下图所示

奥门威尼斯网址 3

Paste_Image.png

一、对象可以实现拷贝的前提

在OC中,若要使对象可以拥有可拷贝操作,则该对象所属的类必须遵守NSCopyingNSMutableCopy协议,并重写copyWithZone:mutableCopyWithZone:方法。
对于自定义类一般只实现NSCopying协议,同时如果遵循了NSCopying协议同时实现了copyWithZone:方法,则实例对象调用copy方法([animal
copy])时会生成一个新的对象,值得注意的是这是一个深拷贝

  • 若自定义类直接继承于NSObject类,则不需要[super copyWithZone:zone]
    ;
  • 若自定义类的父类或者超类继承与NSObject,且其父类或超类均未遵循NSCopying协议,则不需要[super
    copyWithZone:zone] ;
  • 若自定义类的父类或者超类继承与NSObject,且其父类或超类遵循NSCopying协议,则需要[super
    copyWithZone:zone] ;

@interface Animal : NSObject@property (nonatomic,copy) NSString * name;@property (nonatomic,copy) NSString * age;@end@interface Animal()<NSCopying>@end// --------------------------------------------------------@implementation Animal- copyWithZone:zone{ Animal * animal = [[Animal allocWithZone:zone] init]; animal.name = self.name; animal.age = self.age; return animal;}// -----------------------------------------------------//在其他地方调用@implementation ViewController- viewDidLoad { [super viewDidLoad]; Animal * animal = [[Animal alloc] init]; animal.name = @"男儿何惜死"; animal.age = @"27"; Animal * copyAnimal = [animal copy]; NSLog(@"animal.name/age = %@/%@, copyAnimal.name/age = %@/%@", animal.name, animal.age, copyAnimal.name, copyAnimal.age); NSLog(@"animal.address = %p, copyAnimal.address = %p", animal, copyAnimal); }@end
那么如何实现多层复制呢?

我们以NSArray举例说明

 NSArray *copyArray = [[NSArray alloc] initWithArray:array copyItems:YES];  // 完全复制
3.copy和retain的区别

retain不创建指针,不创建对象,只是引用计数+1。
copy创建指针,指针指向旧对象的区域。新对象引用计数为1,一定程度上减少了对旧对象的依赖。

mutableCopy拷贝自定义对象

  • 首先自定义对象需要遵守协议<NSMutableCopying>
  • 其次需要重写方法- (id)mutableCopyWithZone:(NSZone *)zone
  • 但一般没有必要使用mutableCopy拷贝自定义对象,因为使用copy方法拷贝的自定义对象也是可变的,两个方法的作用一样,一般使用copy拷贝自定义对象
二、Copy和MutableCopy的区别

总的来说:如果不可变对象进行复制,copy是指针复制和mutableCopy就是对象复制。如果是对可变对象复制,都是深拷贝。Copy
返回一个不可变对象的副本,MutalbeCopy返回一个可变对象的副本。至于深拷贝到什么地步,下面针对不同情况一一列举:

需要特别注意的是

以上我们所说的两种情况默认都实现了NSCopying和NSMutableCopying协议
对于自定义继承自NSObject的类

  • copy需要实现NSCopying协议,然后实现以下方法,否则copy会crash

-(id)copyWithZone:(NSZone *)zone {
     CopyObject  *copy = [[[self class] alloc] init];
     copy.name = self.name;
     copy.mobile = self.mobile;
     copy.company = self.company;
     copy.descInfo = self.descInfo;
     return copy;
 }
  • mutableCopy时,需要实现NSMutableCopying协议,否则mutableCopy会crash

 -(id)mutableCopyWithZone:(NSZone *)zone {
     MutableCopyObject  *mutableCopy = [[[self class] alloc] init];
     mutableCopy.name = self.name;
     mutableCopy.mobile = self.mobile;
     mutableCopy.company = self.company;
     mutableCopy.descInfo = self.descInfo;
     return mutableCopy;
 }
非容器类对象的拷贝
NSString *str = @"helloWorld";
NSString *strCopy = [str copy];
NSLog(@"%p  %p",str,strCopy);
//打印结果:0x100517068  0x100517068

NSMutableString *str = [[NSMutableString alloc]initWithString:@"helloWorld"];
NSString *strCopy = [str copy];
NSLog(@"%p  %p",str,strCopy);
//打印结果:0x6080000786c0  0x6080000399e0

copy不可变对象:浅拷贝
copy可变对象:深拷贝,but!返回的是不可变对象

NSString *str = @"helloWorld";
NSMutableString *strMutCopy = [str mutableCopy];
[strMutCopy appendFormat:@"!!!"];
NSLog(@"%p  %p  %@",str,strMutCopy,strMutCopy);
//打印结果:0x100c25068  0x60000007a5c0  helloWorld!!!

NSMutableString *str = [[NSMutableString alloc]initWithString:@"helloWorld"];
NSMutableString *strMutCopy = [str mutableCopy];
[strMutCopy appendFormat:@"!!!"];
NSLog(@"%p  %p  %@",str,strMutCopy,strMutCopy);
//打印结果:0x600000264140  0x600000264180  helloWorld!!!

mutableCopy不可变对象or可变对象:都是深拷贝,返回的都是可变对象

对于非容器类对象:copy可变对象返回可变对象,copy不可变对象返回不可变对象,mutableCopy可变不可变都可以返回可变对象。

copy和strong在@property参数中使用的比较

@property (nonatomic, strong) NSString *name;
@property (nonatomic, copy) NSString *name;
  • 如果使用strong,对应的name属性的setter方法是直接赋值(指针拷贝)

    - (void)setName:(NSString *)name
    {
      _name = name;
    }
  • 如果使用copy,对应的name属性的setter方法是先将name对象拷贝(有可能指针拷贝,有可能是内容,取决于具体的对象),然后赋值

    - (void)setName:(NSString *)name
    {
      _name = [name copy];
    }
1、NSString、NSMutableString:
  • 普通字符串NSString/NSMutableString使用copy与mutableCopy的区别:

NSString * string = @"男儿何惜死";NSString * copyString = [string copy];NSMutableString * mutableCopyStr = [string mutableCopy];NSLog(@"string = %p, copyStr = %p mutableCopyStr = %p", string, copyString, mutableCopyStr);NSMutableString * mutableString = [NSMutableString stringWithString:@"破胆与君尝"];NSString * copyMutableStr = [mutableString copy];NSMutableString * mutableCopyMutStr = [mutableString mutableCopy];NSLog(@"mutableString = %p, copyMutableStr = %p mutableCopyMutStr = %p", mutableString, copyMutableStr, mutableCopyMutStr);// ------------------------------------------------// 打印结果:验证了总结的结论string = 0x10e1cf098, copyStr = 0x10e1cf098 mutableCopyStr = 0x600000442520mutableString = 0x600000442550, copyMutableStr = 0x600000442580 mutableCopyMutStr = 0x6000004425b0
  • 对于NSString类来说当作为属性时,关键字@copy与@strong的区别:
    • 当赋予属性值为不可变字符串时,使用@copy和@strong关键字是没有区别的;
    • 当赋予属性值为可变字符串时,需要特别谨慎使用@copy和@strong;因为使用@strong修饰后属性指针与源指针指向同一块内存区域,当该内存中数据发生变化属性值也会变化,这可能不是我们想要看到的。

@property (nonatomic,copy) NSString * name;@property (nonatomic,strong) NSString * strongName;// ----------------------------------------------------NSMutableString * mutableString = [NSMutableString stringWithString:@"男儿何惜死"];self.name = mutableString;self.strongName = mutableString;NSLog(@"mutableString = %p, self.name = %p self.strongName = %p", mutableString, self.name, self.strongName);NSLog(@"mutableString = %@, self.name = %@ self.strongName = %@", mutableString, self.name, self.strongName);[mutableString appendString:@",破胆与君尝"];NSLog(@"mutableString = %@, self.name = %@ self.strongName = %@", mutableString, self.name, self.strongName);// ----------------------------------------------------mutableString = 0x600000241a40, self.name = 0x600000241a70 self.strongName = 0x600000241a40mutableString = 男儿何惜死, self.name = 男儿何惜死 self.strongName = 男儿何惜死mutableString = 男儿何惜死,破胆与君尝, self.name = 男儿何惜死 self.strongName = 男儿何惜死,破胆与君尝
容器类对象的拷贝
NSArray *array = @[@"1",@"2",@"3"];
NSArray *arrayCopy = [array copy];
NSLog(@"%p  %p",array,arrayCopy);
//打印结果:0x60000004f5a0  0x60000004f5a0

NSArray *array = @[@"1",@"2",@"3"];
NSMutableArray *arrayMutableCopy = [array mutableCopy];
[arrayMutableCopy addObject:@"4"];
[arrayMutableCopy replaceObjectAtIndex:0 withObject:@"first"];
NSLog(@"%p  %p  %@",array,arrayMutableCopy,arrayMutableCopy);
/**打印结果:0x600000054250  0x600000053e90  (
    first,
    2,
    3,
    4
)
*/

从以上结果来看,貌似只要对数组进行了mutableCopy,貌似数组和数组元素都深拷贝了……
然鹅……并不是酱紫,是因为我们对数组元素进行了replaceObjectAtIndex操作导致的地址重新创建了。其实,单纯的对数组进行mutableCopy,数组元素是浅拷贝的。于是,用以下代码进行了验证

NSArray *array = @[@"1",@"2",@"3"];
NSArray *arrayCopy = [array copy];
NSMutableArray *arrayMutableCopy = [array mutableCopy];
NSLog(@"%p  %p  %p",array[0],arrayCopy[0],arrayMutableCopy[0]);
//打印结果:0x10f2d5070  0x10f2d5070  0x10f2d5070

所以,如果对容器类对象进行深拷贝连同元素都是创建一个新的地址的话,就要进行如下操作了

NSArray *array = [NSArray arrayWithObjects:[NSMutableString stringWithString:@"1"],@"2",@"3", nil];
NSArray *deepCopyArray = [[NSArray alloc]initWithArray:array copyItems:YES];
NSArray *trueDeepCopyArray = [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:array]];
NSLog(@"%p  %p  %p",array[0],array[1],array[2]);
NSLog(@"%p  %p  %p",deepCopyArray[0],deepCopyArray[1],deepCopyArray[2]);
NSLog(@"%p  %p  %p",trueDeepCopyArray[0],trueDeepCopyArray[1],trueDeepCopyArray[2]);
/**打印结果:
0x608000073140  0x10991b080  0x10991b0a0
0xa000000000000311  0x10991b080  0x10991b0a0
0x608000073440  0xa000000000000321  0xa000000000000331
*/

对于容器类对象:
1.可以用“先归档再解归档”的方法实现容器类及其元素的深拷贝。是真正意义上的深拷贝。
2.initWithArray:
copyItems:方法会对可变元素进行深拷贝,不可变元素进行浅拷贝。

copy在@property参数中使用的注意点

  • 以下代码会出现严重的问题

@property (nonatomic, copy) NSMutableString *name;
  • 分析
    • copy拷贝的对象永远是不可变的,也就是name对象是不可变的,因为它内部赋值方式是_name = [name copy];
    • 使用NSMutableString声明可变的指针指向不可变的name字符串对象,极其不合理,外界以为是NSMutableString类型,一旦调用appendString:方法,会直接报错,因为name对象本质是不可变的;
2、NSArray/NSMutableArray、NSDictionary/NSMutableDictionary、NSSet/NSMutableSet等集合类
自定义对象的拷贝

自定义对象实现拷贝,需要遵循<NSCopying><NSMutableCopying>协议,实现两个方法
- (id)copyWithZone:(NSZone *)zone //可变拷贝
- (id)mutableCopyWithZone:(NSZone *)zone //不可变拷贝

对象内部方法实现:
.h
@property(nonatomic,copy)NSString *name;
@property(nonatomic,strong)NSMutableString *variety;
@property(nonatomic,assign)NSInteger age;
.m
//重写init方法
-(instancetype)init
{
    if (self = [super init]) {
        self.name = @"doggie";
        self.variety = [[NSMutableString alloc]initWithString:@"金毛"];
        self.age = 3;
    }
    return self;
}
//遵循NSCopying协议才能实现此方法
-(id)copyWithZone:(NSZone *)zone
{
    Dog *dog = [[self class]allocWithZone:zone];
    dog.name = [_name copy];
    dog.variety = [_variety copy];
    //基本数据类型直接赋值
    dog.age = _age;
    return dog;
}
//遵循NSMutableCopying协议才能实现此方法
-(id)mutableCopyWithZone:(NSZone *)zone
{
    Dog *dog = [[self class]allocWithZone:zone];
    dog.name = [_name mutableCopy];
    dog.variety = [_variety mutableCopy];
    dog.age = _age;
    return dog;
}
测试代码:
    Dog *dog1 = [[Dog alloc]init];
    Dog *dog2 = [dog1 copy];
    Dog *dog3 = [dog1 mutableCopy];
    NSLog(@"%p %p",dog1.variety,dog1.name);
    NSLog(@"%p %p",dog2.variety,dog2.name);
    NSLog(@"%p %p",dog3.variety,dog3.name);
/**输出结果:
 0x7fdbba4a2910 0x107221098
 0x7fdbba4a2910 0x107221098
 0x7fdbba4a2ad0 0xa00656967676f646
*/

奥门威尼斯网址 4

奥门威尼斯网址 5

奥门威尼斯网址 6

总结一下
1.copy返回的都是不可变对象
2.可变对象都是深拷贝
3.不可变对象copy是浅拷贝,mutableCopy是深拷贝
4.容器对象不用特殊的方法都是单层拷贝

对于常见使用@strong修饰的不可变集合:
@property (nonatomic,strong) NSArray * testArray;// -------------------------------------------------------// 示例一:赋予全部是不可变元素的不可变集合self.testArray = @[@"不负光阴", @"不负卿"];NSArray * test_1 = [self.testArray copy];NSMutableArray * test_2 = [self.testArray mutableCopy];NSLog(@"self.testArray = %p, test_1 = %p, test_2 = %p", self.testArray, test_1, test_2);NSLog(@"\n self.testArray.firstObject = %p, self.testArray.lastObject = %p;\n test_1.firstObject = %p, test_1.lastObject = %p;\n test_2.firstObject = %p, test_2.lastObject = %p", self.testArray[0], self.testArray[1], test_1[0], test_1[1], test_2[0], test_2[1]);// ------------------------------------------------------self.testArray = 0x604000039f60, test_1 = 0x604000039f60, test_2 = 0x60400025d130self.testArray.firstObject = 0x10f61d0a8, self.testArray.lastObject = 0x10f61d0c8;test_1.firstObject = 0x10f61d0a8, test_1.lastObject = 0x10f61d0c8;test_2.firstObject = 0x10f61d0a8, test_2.lastObject = 0x10f61d0c8// ---------------------------------------------------------// 由上可知,虽然mutableCopy是深拷贝,但是不彻底,test_2中的元素与源数组元素依然指向同一块内存区域。// 这在数组元素存在可变元素时会发生奇妙的事情。// 示例二:赋予含有可变元素的不可变集合self.testArray = @[[NSMutableString stringWithString:@"不负光阴"], @"不负卿"];NSArray * test_1 = [self.testArray copy];NSMutableArray * test_2 = [self.testArray mutableCopy];NSLog(@"self.testArray = %@, test_1 = %@, test_2 = %@", self.testArray, test_1, test_2);NSLog(@"self.testArray = %p, test_1 = %p, test_2 = %p", self.testArray, test_1, test_2);NSLog(@"\n self.testArray.firstObject = %p, self.testArray.lastObject = %p;\n test_1.firstObject = %p, test_1.lastObject = %p;\n test_2.firstObject = %p, test_2.lastObject = %p", self.testArray[0], self.testArray[1], test_1[0], test_1[1], test_2[0], test_2[1]);NSMutableString * firstStr = [self.testArray firstObject];[firstStr appendString:@",不负自己"];NSLog(@"self.testArray = %@, test_1 = %@, test_2 = %@", self.testArray, test_1, test_2);// --------------------------------------------------------self.testArray = ( "不负光阴", "不负卿",), test_1 = ( "不负光阴", "不负卿",), test_2 = ( "不负光阴", "不负卿",)self.testArray = 0x60400022bf80, test_1 = 0x60400022bf80, test_2 = 0x604000445100self.testArray.firstObject = 0x604000442430, self.testArray.lastObject = 0x1030c8df8; test_1.firstObject = 0x604000442430, test_1.lastObject = 0x1030c8df8; test_2.firstObject = 0x604000442430, test_2.lastObject = 0x1030c8df8self.testArray = ( "不负光阴,不负自己", "不负卿",), test_1 = ( "不负光阴,不负自己", "不负卿",), test_2 = ( "不负光阴,不负自己", "不负卿",)// --------------------------------------------------------// 可以看到所有数组的第一个元素全部发生了改变。同样数组内即使存在可变数元素,外部使用mutableCopy,内部元素依然指向同一块内存区域!// 试想一下如果 将[firstStr appendString:@",不负自己"];// 改为 firstStr = [NSMutableString stringWithString:@"不负光阴,不负自己"];//打印结果如何?为什么?// 示例三:赋予可变集合(这里与NSString相似)NSMutableArray * baseArray = [NSMutableArray arrayWithArray:@[@"不负光阴", @"不负卿"]];self.testArray = baseArray;NSArray * test_1 = [self.testArray copy];NSMutableArray * test_2 = [self.testArray mutableCopy];NSLog(@"baseArray = %p, self.testArray = %p, test_1 = %p, test_2 = %p", baseArray, self.testArray, test_1, test_2);NSLog(@"baseArray = %@, self.testArray = %@", baseArray, self.testArray);[baseArray addObject:@"不负自己"];NSLog(@"baseArray = %@, self.testArray = %@", baseArray, self.testArray);// ----------------------------------------------------------baseArray = 0x6000004442f0, self.testArray = 0x6000004442f0, test_1 = 0x6000000342e0, test_2 = 0x600000444320baseArray = ( "不负光阴", "不负卿",), self.testArray = ( "不负光阴", "不负卿",)baseArray = ( "不负光阴", "不负卿", "不负自己",), self.testArray = ( "不负光阴", "不负卿", "不负自己",)// ----------------------------------------------------------// 赋值操作是一个浅拷贝的过程;// 可以看到当源数据发生变化时self.testArray也与之变化,这可能也不是我们想看到到~
使用@copy关键字修饰的不可变集合:

当赋予其不可变集合对象时与@strong没有区别,对其进行copy或者mutableCopy操作与中示例一、二情况一致,即copy操作生成的对象与原对象指向同一块内存区域,mutableCopy则不同;
当对其赋予可变集合时,由于是@copy修饰,此时虽然是赋值操作同时也是一个深拷贝的过程,会在一个新的内存地址来存储@copy修饰的集合,集合内元素的地址与源集合中元素地址依然一样,但是此时再修改源集合,目标集合不会再改变!

@property (nonatomic,copy) NSArray * testCopyArray;// -------------------------------------------------------------------NSMutableArray * baseArray = [NSMutableArray arrayWithArray:@[@"不负光阴", @"不负卿"]];self.testCopyArray = baseArray;NSArray * test_1 = [self.testCopyArray copy];NSMutableArray * test_2 = [self.testCopyArray mutableCopy];NSLog(@"baseArray = %p, self.testCopyArray = %p, test_1 = %p, test_2 = %p", baseArray, self.testCopyArray, test_1, test_2);NSLog(@"baseArray = %@, self.testCopyArray = %@", baseArray, self.testCopyArray);[baseArray addObject:@"不负自己"];NSLog(@"baseArray = %@, self.testCopyArray = %@", baseArray, self.testCopyArray);// ------------------------------------------------------------------- baseArray = 0x60400025de80, self.testCopyArray = 0x60400022bb60, test_1 = 0x60400022bb60, test_2 = 0x60400025deb0 baseArray = ( "不负光阴", "不负卿",), self.testCopyArray = ( "不负光阴", "不负卿",)baseArray = ( "不负光阴", "不负卿", "不负自己",), self.testCopyArray = ( "不负光阴", "不负卿",)// -------------------------------------------------------------------// 是不是觉得使用@copy修饰的不可变集合更靠谱一些😂// 同时需要注意的是:对于不可变数组,不管用什么修饰,不管给予其赋值的是可变还是不可变的数组,copy操作生成的对象与原对象均指向同一块内存区域!!!
使用@strong修饰的可变集合:
// 与中的第三种情况相似@property (nonatomic,strong) NSMutableArray * testArray; // ---------------------------------------------------------------NSMutableArray * baseArray = [NSMutableArray arrayWithArray:@[@"不负光阴", @"不负卿"]];self.testArray = baseArray;NSArray * test_1 = [self.testArray copy];NSMutableArray * test_2 = [self.testArray mutableCopy];NSLog(@"baseArray = %p, self.testArray = %p, test_1 = %p, test_2 = %p", baseArray, self.testArray, test_1, test_2);NSLog(@"baseArray = %@, self.testArray = %@", baseArray, self.testArray);[baseArray addObject:@"不负自己"];NSLog(@"baseArray = %@, self.testArray = %@", baseArray, self.testArray);// -------------------------------------------------------------------baseArray = 0x6000004496c0, self.testArray = 0x6000004496c0, test_1 = 0x6000000307c0, test_2 = 0x6000004496f0baseArray = ( "不负光阴", "不负卿",), self.testArray = ( "不负光阴", "不负卿",)baseArray = ( "不负光阴", "不负卿", "不负自己",), self.testArray = ( "不负光阴", "不负卿", "不负自己",)
使用@copy修饰的可变集合:
// 为其赋值等操作均没啥问题,问题出在将其作为一个值,赋予其他可变集合时!@property (nonatomic,copy) NSMutableArray * testCopyArray;// -------------------------------------------------------------------self.testCopyArray = [NSMutableArray arrayWithArray:@[@"不负光阴", @"不负卿"]];NSMutableArray * baseArray = [NSMutableArray array];baseArray = self.testCopyArray;NSLog(@"baseArray = %p, self.testCopyArray = %p", baseArray, self.testCopyArray);[self.testCopyArray addObject:@"不负自己"];[baseArray addObject:@"不负自己"];// -------------------------------------------------------------------//此时会崩溃baseArray = 0x60400022acc0, self.testCopyArray = 0x60400022acc0-[__NSArrayI addObject:]: unrecognized selector sent to instance 0x60400022acc0// 可以看到baseArray已经是一个不可变的集合,所以对其进行增删等操作会引发异常。// 原因就是因为修饰词是@copy,我们上面已经强调了copy操作返回不可变对象,// mutableCopy返回可变对象,这与是否是深拷贝与浅拷贝无关,要切记。

以上均是用数组举例,其实字典等也相似的,可以自行尝试一下。这里给出一个简单的🌰

@property (nonatomic,strong) NSDictionary * testDic;// ---------------------------------------------------------------------NSMutableDictionary * dic = [NSMutableDictionary dictionaryWithDictionary:@{@"001" : @"男儿何惜死", @"002" : @"破胆与君尝"}];self.testDic = dic;NSDictionary * test_1 = [self.testDic copy];NSMutableDictionary * test_2 = [self.testDic mutableCopy];NSLog(@"dic = %p, self.testDic = %p, test_1 = %p, test_2 = %p", dic, self.testDic, test_1, test_2);NSLog(@"dic = %@, self.testDic = %@", dic, self.testDic);[dic setObject:@"两情若是久长时" forKey:@"003"];NSLog(@"dic = %@, self.testDic = %@", dic, self.testDic);// ---------------------------------------------------------------------dic = 0x604000030320, self.testDic = 0x604000030320, test_1 = 0x604000030340, test_2 = 0x604000030360dic = { 001 = "男儿何惜死", 002 = "破胆与君尝",}, self.testDic = { 001 = "男儿何惜死", 002 = "破胆与君尝",}dic = { 001 = "男儿何惜死", 002 = "破胆与君尝", 003 = "两情若是久长时",}, self.testDic = { 001 = "男儿何惜死", 002 = "破胆与君尝", 003 = "两情若是久长时",}
三、集合的真正的深拷贝

上面提到集合的深拷贝并不彻底,集合内的元素的地址依然是相同的,那么如何实现集合的真正的拷贝呢?参考文档

// 可以将该集合归档然后再解档,前提是内容均符合NSCoding协议,这样可以得到一个真正意义上的深拷贝。@property (nonatomic,strong) NSArray * testArray;// ---------------------------------------------------------------------self.testArray = @[@"不负光阴", @"不负卿"];NSArray * deepArray = [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:self.testArray]];NSLog(@"self.testArray = %p, deepArray = %p", self.testArray, deepArray);NSLog(@"self.testArray = %@, deepArray = %@", self.testArray, deepArray);NSLog(@"self.testArray[0] = %p, self.testArray[1] = %p, deepArray[0] = %p, deepArray[1] = %p", self.testArray[0], self.testArray[1], deepArray[0], deepArray[1]);// ---------------------------------------------------------------------self.testArray = 0x604000229b60, deepArray = 0x604000229be0self.testArray = ( "不负光阴", "不负卿",), deepArray = ( "不负光阴", "不负卿",)self.testArray[0] = 0x10350d238, self.testArray[1] = 0x10350d258, deepArray[0] = 0x604000229c20, deepArray[1] = 0x604000229b80

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图