深拷贝和浅拷贝

浅拷贝就是你和张三放一个风筝,
深拷贝就是你买了一个跟张三一模一样的风筝.

浅拷贝: 也叫位拷贝,只对指针的拷贝,拷贝后两个指针指向同一个内存空间.

深拷贝: 也叫值拷贝,对指针进行拷贝,而且对指针指向的内容进行拷贝,经深拷贝后的指针是指向两个不同地址的指针.

NSString *srcStr = @"123";
NSMutableString *copyStr =  [srcStr mutableCopy];
[copyStr appendString:@"abc"];
NSLog(@"srcStr=%p:%@, copyStr=%p:%@", srcStr,srcStr, copyStr,copyStr);

浅拷贝会出现什么问题?

  1. 浅拷贝只拷贝了指针,使得两个指针指向同一个地址,对象释放时,会造成同一份资源析构2次,造成程序崩溃.也就会引起常见的僵尸对象(zombie).
  2. 浅拷贝指针指向同一块内存,任何一方的变动都会影响到另一方.

深拷贝会出现什么问题?

深拷贝都是在堆内存中申请新的空间来存储数据,可以避免指针悬挂.

  1. 都使用深拷贝会造成资源浪费.
  2. 深拷贝只能拷贝一层,要想拷贝第二层,必须是第二层的对象也实现NSCopy协议.
NSArray *array = @[@"1",@"2",@"3"];
NSMutableArray *mutableArray = [array mutableCopy];
[mutableArray addObject:@"4"];

NSLog(@"array地址:%p,array=%@\nmutableArray地址:%p,mutableArray=%@",array,array,mutableArray,mutableArray);

NSCopying和NSMutableCopying

自定义类想要支持 copymutableCopy 方法就需要实现 NSCopyingNSMutableCopying 协议。

@interface People : NSObject <NSCopying,NSMutableCopying>
@property (nonatomic,copy) NSString *name;
@end

@implementation People

- (id)init
{
    self = [super init];
    if (self) {
        self.name = @"";
    }
    return self;
}
// copyWithZone: 方法相当于创建一个新对象,并将当前对象的值复制到新创建的对象中。设置时应直接访问成员变量而不是属性。
- (id)copyWithZone:(nullable NSZone *)zone
{
    // 直接从 NSObject 继承的类应该使用此方法
    // 父类已经实现此方法的应该调用 [super copyWithZone:zone]
    People *p = [[self class] allocWithZone:zone];
    p.name = [_name copyWithZone:zone];
    return p;
}

- (id)mutableCopyWithZone:(nullable NSZone *)zone
{
    People *p = [[self class] allocWithZone:zone];
    p.name = [_name mutableCopyWithZone:zone];
    return p;
}
@end
People *p1 = [[People alloc] init];
p1.name = @"1";

People *p2 = [People new];
p2.name = @"2";

People *p3 = [People new];
p3.name = @"3";

NSArray *array = @[p1,p2,p3];
NSMutableArray *mutableArray = [array mutableCopy];

People *pe3 = mutableArray[2];
pe3.name = @"pe3";

People *pe4 = [People new];
pe4.name = @"3";
[mutableArray addObject:pe4];

//copy和mutableCopy的区别
People *pe33 = [pe3 copy];
People *pe333 = [pe3 mutableCopy];
pe333.name = @"pe333";
NSLog(@"array地址:%p,array=%@\nmutableArray地址:%p,mutableArray=%@",array,array,mutableArray,mutableArray);

log日志:

array地址:0x6000000509b0,array=(
    "<People: 0x60000000f670>",
    "<People: 0x60000000f680>",
    "<People: 0x60000000f690>"
)
mutableArray地址:0x6000000509e0,mutableArray=(
    "<People: 0x60000000f670>",
    "<People: 0x60000000f680>",
    "<People: 0x60000000f690>",
    "<People: 0x60000000f0f0>"
)

在对array进行mutableCopy后,数组地址发生了改变,但是数组内people对象的地址并未发生改变.