前言
- 浅拷贝,对内存地址的拷贝,目标对象指针和原对象指针指向同一片内存区域。当内存被销毁时,所有指向这片内存的对象指针都成为了野指针,必须重新定义才可继续使用。
- 深拷贝,对具体内容的拷贝,目标对象指针和原对象指针指向不同的内存区域,这两块内存区域内存储的值是相同的。新的内存地址由系统自主分配,新旧对象互不影响、互不干涉。
验证
下面通过代码,简单验证下:验证工程GitHub链接
NSString / NSMutableString
// NSString
- (void)testString{
NSString *str = @"Jack and Rose";
NSString *cStr = [str copy];
NSMutableString *mcStr = [str mutableCopy];
NSLog(@"=== NSString Test ===");
NSLog(@"str: %p : %@",str, str);
NSLog(@"cStr: %p : %@",cStr, cStr);
NSLog(@"mcStr: %p : %@",mcStr, mcStr);
}
- 对
NSString
对象进行copy
操作,新旧对象指向同一块内存区域,即拷贝的是指针,是浅拷贝。 - 对
NSString
对象进行mutableCopy
操作,新旧对象指向两块不同的内存区域,新对象开辟了一块新的内存区域,两块内存区域内存储的值是相同的,即拷贝的是内容,是深拷贝。
// NSMutableString
- (void)testMutableString{
NSMutableString *str = [NSMutableString stringWithString:@"Jack and Rose"];
NSString *cStr = [str copy];
NSMutableString *mcStr = [str mutableCopy];
NSLog(@"=== NSMutableString Test ===");
NSLog(@"str: %p : %@",str, str);
NSLog(@"cStr: %p : %@",cStr, cStr);
NSLog(@"mcStr: %p : %@",mcStr, mcStr);
}
- 对
NSMutableString
对象进行copy
操作,新旧对象指向两块不同的内存区域,新对象开辟了一块新的内存区域,两块内存区域内存储的值是相同的,即拷贝的是内容,是深拷贝。 - 对
NSMutableString
对象进行mutableCopy
操作,同copy
操作一样也是深拷贝,不同点在于copy
操作返回的新对象为NSString
不可变类型,mutableCopy
操作返回的新对象为NSMutableString
可变类型。
NSArray / NSMutableArray
// NSArray
- (void)testArray{
NSMutableArray *subArr = [NSMutableArray arrayWithArray:@[@"Jack"]];
NSArray *arr = @[subArr];
NSArray *cArr = [arr copy];
NSMutableArray *mcArr = [arr mutableCopy];
NSLog(@"=== NSArray Test ===");
NSLog(@"arr: %p : %@",arr, arr);
NSLog(@"cArr: %p : %@",cArr, cArr);
NSLog(@"mcArr: %p : %@",mcArr, mcArr);
subArr = [NSMutableArray arrayWithArray:@[@"Jack", @"Rose"]];
NSLog(@"=== NSArray Test - subArr reinit===");
NSLog(@"arr: %p : %@",arr, arr);
NSLog(@"cArr: %p : %@",cArr, cArr);
NSLog(@"mcArr: %p : %@",mcArr, mcArr);
[subArr addObject:@"Rose"];
NSLog(@"=== NSArray Test - subArr add object===");
NSLog(@"arr: %p : %@",arr, arr);
NSLog(@"cArr: %p : %@",cArr, cArr);
NSLog(@"mcArr: %p : %@",mcArr, mcArr);
}
- 对
NSArray
对象进行copy
操作,新旧对象指向同一块内存区域,即拷贝的是指针,是浅拷贝。 - 对
NSArray
对象进行mutableCopy
操作,新旧对象指向两块不同的内存区域,新对象开辟了一块新的内存区域,两块内存区域内存储的值是相同的,即拷贝的是内容,是深拷贝。
⚠️然后进一步来看,当我们对数组内部元素(此处指subArr
)进行变动时,对原对象及拷贝对象的影响:
操作一: [subArr addObject:@"Rose"];
该操作向subArr
中再添加了一个元素Rose
,log如下:
操作二: subArr = [NSMutableArray arrayWithArray:@[@"Jack and Rose"]];
该操作将subArr
重新进行初始化并赋值,log如下:
对比控制台log可以看出,操作一对NSArray
原对象和拷贝对象都产生了影响,其指向的指针没有变,但内容发生了变化;操作二对NSArray
原对象和拷贝对象都没有产生影响,其指向的指针和该指针指向内存区域内的值都没有发生变化。这是为什么呢?
原因在于,NSArray
在进行copy
操作时,内部子元素总是以浅拷贝的方式被复制(mutableCopy同
)。操作一
改变了数组内子元素所指向内存区域内的值,故对应数组内的值也发生了改变;操作二
虽然也改变了subArr
的值,但经过重新初始化赋值后的subArr
与数组内子元素已经不再指向同一块内存区域,所以改变subArr
的值对数组内子元素不造成影响。
// NSMutableArray
- (void)testMutableArray{
NSMutableArray *subArr = [NSMutableArray arrayWithArray:@[@"Jack"]];
NSMutableArray *arr = [NSMutableArray arrayWithArray:@[subArr]];
NSArray *cArr = [arr copy];
NSMutableArray *mcArr = [arr mutableCopy];
NSLog(@"=== NSMutableArray Test ===");
NSLog(@"arr: %p : %@",arr, arr);
NSLog(@"cArr: %p : %@",cArr, cArr);
NSLog(@"mcArr: %p : %@",mcArr, mcArr);
[subArr addObject:@"Rose"];
NSLog(@"=== NSMutableArray Test - subArr add object===");
NSLog(@"arr: %p : %@",arr, arr);
NSLog(@"cArr: %p : %@",cArr, cArr);
NSLog(@"mcArr: %p : %@",mcArr, mcArr);
subArr = [NSMutableArray arrayWithArray:@[@"Jack and Rose"]];
NSLog(@"=== NSMutableArray Test - subArr reinit===");
NSLog(@"arr: %p : %@",arr, arr);
NSLog(@"cArr: %p : %@",cArr, cArr);
NSLog(@"mcArr: %p : %@",mcArr, mcArr);
}
- 对
NSMutableArray
对象进行copy
操作,新旧对象指向两块不同的内存区域,新对象开辟了一块新的内存区域,两块内存区域内存储的值是相同的,即拷贝的是内容,是深拷贝。 - 对
NSMutableArray
对象进行mutableCopy
操作,同copy
操作一样也是深拷贝,不同点在于copy
操作返回的新对象为NSArray
不可变类型,mutableCopy
操作返回的新对象为NSMutableArray
可变类型。 - 对数组内部子元素进行操作,影响同
NSArray
NSDictionary / NSMutableDictionary
同NSArray / NSMutableArray。
总结
原对象类型 | 拷贝方法 | 副本对象类型 | 是否产生新对象 | 拷贝类型 |
---|---|---|---|---|
NS* | copy | NS* | NO | 浅拷贝(拷贝指针) |
NSMutable* | copy | NS* | YES | 深拷贝(拷贝内容) |
NS* | mutableCopy | NSMutable* | YES | 深拷贝(拷贝内容) |
NSMutable* | mutableCopy | NSMutable* | YES | 深拷贝(拷贝内容) |