美文网首页
问题:请问深拷贝和浅拷贝有什么区别?

问题:请问深拷贝和浅拷贝有什么区别?

作者: 姜小舟 | 来源:发表于2020-05-12 19:24 被阅读0次
  • 深拷贝:深拷贝直接拷贝对象到内存中一块区域,然后把新对象的指针指向这块内存,复制的对象指向了新的地址
  • 浅拷贝:浅拷贝并不拷贝对象本身,只是对指向对象的指针进行拷贝,复制的对象和原对象都指向同一个地址

深拷贝(MutableCopy)与浅拷贝(Copy)

  • copy: 对于可变对象为深拷贝,对于不可变对象为浅拷贝
  • mutableCopy:始终是深拷贝
  • 容器中包含对象的拷贝,无论是copy,还是mutablecopy对容器中包含的对象都是浅拷贝,要想实现对象的深拷贝,必须自己提供拷贝方法。

下面将结合代码来对copy和mutableCopy进行分析:

在开发过程中,大体上会区分为非容器对象容器对象两个概念。

  • 非容器不可变对象:NSString
  • 费容器可变对象: NSMutableString
  • 容器类不可变对象: NSArray
  • 容器类可变对象: NSMutableArray
  • 非容器不可变对象
NSString *str1 = @"非容器不可变对象";
NSString *str2 = [str1 copy];
NSString *str3 = [str1 mutableCopy];

NSLog(@"str1_p : %p, class: %@", str1, [str1 class]);
NSLog(@"str2_p : %p, class: %@", str2, [str2 class]);
NSLog(@"str3_p : %p, class: %@", str3, [str3 class]);
输出:
str1_p : 0x104c4a068, class: __NSCFConstantString
str2_p : 0x104c4a068, class: __NSCFConstantString
str3_p : 0x61000006db00, class: __NSCFString

#结论:
#- 对于非容器不可变对象的copy为浅拷贝,mutableCopy为深拷贝
#- 浅拷贝获得的对象地址和原对象地址一致, 返回的对象为不可变对象
#- 深拷贝返回新的内存地址,返回对象为可变对象
  • 非容器可变对象
NSMutableString *str1 = [NSMutableString stringWithFormat:@"非容器可变对象"];
NSMutableString *str2 = [str1 copy];
NSMutableString *str3 = [str1 mutableCopy];

NSLog(@"str1_p : %p, class: %@", str1, [str1 class]);
NSLog(@"str2_p : %p, class: %@", str2, [str2 class]);
NSLog(@"str3_p : %p, class: %@", str3, [str3 class]);
输出:
str1_p : 0x618000260140, class: __NSCFString
str2_p : 0x61800004efd0, class: __NSCFString
str3_p : 0x6180002602c0, class: __NSCFString

#结论:
#- 对于非容器可变对象的copy为深拷贝,mutableCopy为深拷贝
#- 并且copy和mutableCopy返回对象都为可变对象
  • 容器不可变对象
NSMutableString *str1 = [NSMutableString stringWithFormat:@"非容器可变对象"];
NSArray *array = [NSArray arrayWithObjects:str1, @"非容器不可变对象", nil];
NSArray *copyArray = [array copy];
NSArray *mutableCopyArray = [array mutableCopy];

NSLog(@"array_p: %p, class: %@", array, [array class]);
NSLog(@"copyArray_p: %p, class: %@", copyArray, [copyArray class]);
NSLog(@"mutableCopyArray_p: %p, class: %@", mutableCopyArray, [mutableCopyArray class]);
    
NSLog(@"======原对象=====");
NSLog(@"object_p: %p, class: %@", array[0], [array[0] class]);
NSLog(@"object_p: %p, class: %@", array[1], [array[1] class]);
    
NSLog(@"======copy对象=====");
NSLog(@"object_p: %p, class: %@", copyArray[0], [copyArray[0] class]);
NSLog(@"object_p: %p, class: %@", copyArray[1], [copyArray[1] class]);
    
NSLog(@"======mutableCopy对象=====");
NSLog(@"object_p: %p, class: %@", mutableCopyArray[0], [mutableCopyArray[0] class]);
NSLog(@"object_p: %p, class: %@", mutableCopyArray[1], [mutableCopyArray[1] class]);

输出:

array_p: 0x610000024ac0, class: __NSArrayI
copyArray_p: 0x610000024ac0, class: __NSArrayI
mutableCopyArray_p: 0x610000242610, class: __NSArrayM

======原对象=====
object_p: 0x61000006f540, class: __NSCFString
object_p: 0x10c386080, class: __NSCFConstantString

======copy对象=====
object_p: 0x61000006f540, class: __NSCFString
object_p: 0x10c386080, class: __NSCFConstantString

======mutableCopy对象=====
object_p: 0x61000006f540, class: __NSCFString
object_p: 0x10c386080, class: __NSCFConstantString

#结论:
#容器类不可变对象mutableCopy确实返回一个新的容器,但容器内的元素仍然是浅拷贝
  • 容器可变对象
NSMutableString *str1 = [NSMutableString stringWithFormat:@"非容器可变对象"];
    
NSMutableArray *array = [NSMutableArray arrayWithObjects:str1, @"非容器不可变对象", nil];
NSMutableArray *copyArray = [array copy];
NSMutableArray *mutableCopyArray = [array mutableCopy];
    
NSLog(@"array_p: %p, class: %@", array, [array class]);
NSLog(@"copyArray_p: %p, class: %@", copyArray, [copyArray class]);
NSLog(@"mutableCopyArray_p: %p, class: %@", mutableCopyArray, [mutableCopyArray class]);
    
NSLog(@"======原对象=====");
NSLog(@"object_p: %p, class: %@", array[0], [array[0] class]);
NSLog(@"object_p: %p, class: %@", array[1], [array[1] class]);
    
NSLog(@"======copy对象=====");
NSLog(@"object_p: %p, class: %@", copyArray[0], [copyArray[0] class]);
NSLog(@"object_p: %p, class: %@", copyArray[1], [copyArray[1] class]);
    
NSLog(@"======mutableCopy对象=====");
NSLog(@"object_p: %p, class: %@", mutableCopyArray[0], [mutableCopyArray[0] class]);
NSLog(@"object_p: %p, class: %@", mutableCopyArray[1], [mutableCopyArray[1] class]);
输出:
array_p: 0x6100000552d0, class: __NSArrayM
copyArray_p: 0x610000031340, class: __NSArrayI
mutableCopyArray_p: 0x610000055000, class: __NSArrayM

======原对象=====
object_p: 0x610000267300, class: __NSCFString
object_p: 0x107070080, class: __NSCFConstantString

======copy对象=====
object_p: 0x610000267300, class: __NSCFString
object_p: 0x107070080, class: __NSCFConstantString

======mutableCopy对象=====
object_p: 0x610000267300, class: __NSCFString
object_p: 0x107070080, class: __NSCFConstantString

#结论:
#容器类可变对象mutableCopy和copy都返回一个新的容器,但容器内的元素仍然是浅拷贝
  • 自定义类对象的深浅拷贝

在iOS中并不是所有对象都支持Copy和MutableCopy,遵循NSCopying协议的类可以发送Copy协议,遵循NSMutableCopying协议的类可以发送MutableCopy消息。如果一个对象没有遵循这两个协议而发送Copy或者MutableCopy消息那么会发生异常。如果要遵循NSCopying协议,那么必须实现copyWithZone方法。如果要遵循NSMutableCopying协议那么必须实现mutableCopyWithZone方法。如果没有遵循,拷贝时会直接Crash。
代码示例:

-------------------------------------
//Person.h
#import <Foundation/Foundation.h>
@interface Person : NSObject <NSCopying, NSMutableCopying>
@property (nonatomic, copy) NSString *name;
@end
-------------------------------------
//Person.m
#import "Person.h"
@implementation Person
- (id)copyWithZone:(NSZone *)zone {
    Person *person = [Person allocWithZone:zone];
    person.name = self.name;
    return person;
}
- (id)mutableCopyWithZone:(NSZone *)zone {
    Person *person = [Person allocWithZone:zone];
    person.name = self.name;
    return person;
}
@end
-------------------------------------
#实现容器对象的完全拷贝

NSMutableString *str1 = [NSMutableString stringWithFormat:@"非容器可变对象"];
NSArray *array = [NSArray arrayWithObjects:str1, @"非容器不可变对象", nil];
NSMutableArray *mutableArray = [[NSMutableArray alloc] initWithArray:array copyItems:YES];
    
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:mutableArray];
NSMutableArray *newMutableArray = [NSKeyedUnarchiver unarchiveObjectWithData:data];
    
NSLog(@"===原对象===");
NSLog(@"array[0] : %p, array[1] : %p", array[0], array[1]);
    
NSLog(@"===新对象===");
NSLog(@"mutableArray[0] : %p, mutableArray[1] : %p", mutableArray[0], mutableArray[1]);
    
NSLog(@"===完全拷贝对象===");
NSLog(@"newMutableArray[0] : %p, newMutableArray[1] : %p", newMutableArray[0], newMutableArray[1]);
输出:
===原对象===
array[0] : 0x6180000697c0, array[1] : 0x10f40f098
===新对象===
mutableArray[0] : 0x618000055060, mutableArray[1] : 0x10f40f098
===完全拷贝对象===
newMutableArray[0] : 0x618000055600, newMutableArray[1] : 0x6180000556f0

如果是自定义类对象 需要遵循<NSCoding>否则在使用NSKeyedArchiver的时候会Crash
自定义对象代码如下:

-------------------------------------
//Person.h
#import <Foundation/Foundation.h>
@interface Person : NSObject <NSCoding>
@property (nonatomic, copy) NSString *name;
@end
-------------------------------------
//Person.m
#import "Person.h"
@implementation Person
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
    self.name = [aDecoder decodeObjectForKey:@"name"];
    return self;
}
- (void)encodeWithCoder:(NSCoder *)aCoder {
    [aCoder encodeObject:self.name forKey:@"name"];
}
@end
-------------------------------------

相关文章

网友评论

      本文标题:问题:请问深拷贝和浅拷贝有什么区别?

      本文链接:https://www.haomeiwen.com/subject/qchinhtx.html