Objective-C中的浅拷贝&深拷贝

首先介绍一下浅拷贝和深拷贝的概念。

  • 浅拷贝:是指针拷贝,让拷贝前和拷贝后对象的指针指向同一块内存地址。
  • 增加了拷贝前原对象的引用计数
  • 没有新的内存分配
  • 深拷贝:是内存拷贝,让拷贝前和拷贝后对象的指针 指向内容相同的两块内存地址。
  • 不会增加引用计数
  • 产生新的内存分配

1. 系统类对象的浅拷贝和深拷贝

下面通过代码 看一下对于可变对象和不可变对象的深拷贝、浅拷贝的区别:

NSString * myString = @"this is a string";
NSString * myStringCopy = [myString copy];
NSMutableString * myStringMutableCopy = [myString mutableCopy];
NSLog(@"myString的地址 = %p",myString);
NSLog(@"myStringCopy的地址 = %p",myStringCopy);
NSLog(@"myStringMutableCopy的地址 = %p",myStringMutableCopy);
        
NSMutableString * myMutableString = [[NSMutableString alloc]initWithString:@"this is a mutableString"];
NSString * myMutableStringCopy = [myMutableString copy];
NSMutableString * myMutableStringMutableCopy = [myMutableString mutableCopy];
NSLog(@"myMutableString的地址 = %p",myMutableString);
NSLog(@"myMutableStringCopy的地址 = %p",myMutableStringCopy);
NSLog(@"myMutableStringMutableCopy的地址 = %p",myMutableStringMutableCopy);

运行上面代码打印如下:

// 不可变对象拷贝打印
myString的地址 = 0x1006b21e0
myStringCopy的地址 = 0x1006b21e0
myStringMutableCopy的地址 = 0x6000037ba340
// 可变对象拷贝打印
myMutableString的地址 = 0x6000037b9ef0
myMutableStringCopy的地址 = 0x6000037b9fb0
myMutableStringMutableCopy的地址 = 0x6000037ba370

结论:

  • 对于不可变对象

copy 是浅拷贝 生成的对象是不可变对象。
mutableCopy 是深拷贝 生成的对象是可变对象。

  • 对于可变对象

copy 是深拷贝 生成的对象是不可变对象。
mutableCopy 是深拷贝 生成的是可变对象。

2. 自定义类对象的浅拷贝和深拷贝

在Objective-C语言中 不是所有类都支持拷贝。
只有遵循协议才支持copy方法,
只有遵循协议才支持mutableCopy方法,否则会造成崩溃。

这里需要注意父类和子类都实现协议情况

// 父类实现copyWithZone方法
@implementation MyBlockObject
- (id) copyWithZone:(NSZone *)zone{
// 这里是重点注意的地方
    MyBlockObject * blk = [[[self class] alloc]init];
    blk.blockObjectStr = self.blockObjectStr;
    return blk;
}
@end
// 子类实现copyWithZone方法
@implementation MyBlockSubObject
- (id)copyWithZone:(NSZone *)zone{
    MyBlockSubObject * subObj = [super copyWithZone:zone];
    subObj.mysubString = self.mysubString;
    return subObj;
}
@end

3.copy作为属性修饰符

根据上面1中得出的结论

copy操作对于不可变对象是浅拷贝,对于可变对象是深拷贝。生成的都是不可变对象。所以copy一般作为不可变类型的属性修饰符。

@interface ViewController ()
// 对不可变对象进行copy操作后的目标对象
@property (nonatomic, copy) NSString * myCopyimmutableStringString;
// 对可变对象进行copy操作后的目标对象
@property (nonatomic, copy) NSString * myCopyMutableString;

@end
@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    NSString * immutableString = @"this is immutableString.";
    self.myCopyimmutableStringString = immutableString;
    NSLog(@"immutableString的地址 = %p    self.myCopyimmutableStringString的地址 = %p",immutableString,self.myCopyimmutableStringString);

    NSMutableString * mutableString = [[NSMutableString alloc]initWithString:@"this is mutableString."];
    self.myCopyMutableString = mutableString;
    NSLog(@"mutableString的地址 = %p    self.myCopyMutableString的地址 = %p",mutableString,self.myCopyMutableString);
    [mutableString appendString:@"!!!"];
    NSLog(@"self.myCopyMutableString 的值:%@",self.myCopyMutableString);
}

@end

打印结果

immutableString的地址 = 0x10d1ac220 
self.myCopyimmutableStringString的地址 = 0x10d1ac220

mutableString的地址 = 0x600002839b00   
self.myCopyMutableString的地址 = 0x6000028399b0
// 赋值对象发生改变不会影响原对象的值
self.myCopyMutableString 的值:this is mutableString.

结论:

copy作为属性修饰符在赋值时
如果赋值对象为不可变对象,那发生的是浅拷贝;
如果赋值的对象是可变对象,那发生的是深拷贝;
从而保证了在赋值对象发生改变时,不会影响copy修饰的对象的值。

这里也证明了 为什么对于不可变类的最好不要使用strong作为修饰符。是因为strong作为属性修饰符,在赋值时是浅拷贝。在赋值对象是可变对象时,赋值对象改变会影响原对象的值。

你可能感兴趣的:(Objective-C中的浅拷贝&深拷贝)