首先介绍一下浅拷贝和深拷贝的概念。
- 浅拷贝:是指针拷贝,让拷贝前和拷贝后对象的指针指向同一块内存地址。
- 增加了拷贝前原对象的引用计数
- 没有新的内存分配
- 深拷贝:是内存拷贝,让拷贝前和拷贝后对象的指针 指向内容相同的两块内存地址。
- 不会增加引用计数
- 产生新的内存分配
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语言中 不是所有类都支持拷贝。
只有遵循<NSCopying>协议才支持copy方法,
只有遵循<NSMutableCopying>协议才支持mutableCopy方法,否则会造成崩溃。
这里需要注意父类和子类都实现<NSCopying>协议情况
// 父类实现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作为属性修饰符,在赋值时是浅拷贝。在赋值对象是可变对象时,赋值对象改变会影响原对象的值。
网友评论