经常在论坛和群里看到有人问拷贝相关的问题,回答的总是五花八门、千奇百怪。如果你对几种拷贝的概念还不是很清晰,这篇文章会有帮助。
什么是浅拷贝
在谈论深拷贝、浅拷贝等概念之前,先要清楚什么叫拷贝。拷贝(copy)就是复制。当我们已经有一个对象例如:
NSString *str = @"abc";
那么我想有一个str2和str的值一样该怎么做呢?最简单的办法就是这样:
NSString *str2 = str;
实际上,这就是浅拷贝,str和str2的内存地址是一样的。也就是说两个指针指向了同一块内存,因此实际上并没有东西被复制出来,就好比文件的快捷方式,无论一个文件有多少快捷方式,这个文件始终只有一个。那么如果我不想要快捷方式,就想要两个文件呢?
NSString *str3 = [str copy];
理论上来说,这样会划分新的内存地址,生成新的对象,但是实际打印会发现str和str3的地址是一样的。这是因为OC对NSString做了内存管理的优化,这种值相同的string会直接浅拷贝。这也说明,正常情况下NSString是不需要深拷贝的。
什么是深拷贝
那么什么时候需要深拷贝呢?其实深拷贝在开发中经常用到:
@property (nonatomic, copy) NSString *name;
类似这样的属性项目中肯定多的数不清(当然如果你写成@property (nonatomic, strong) NSString *name;
是不对的,你的项目会有可能出现莫名其妙的bug)。见名知意,声明为copy的属性在被赋值的时候实际上是会执行copy方法的,就像这样:
- (void)setName:(NSString *)name{
_name = [name copy];
}
为什么要这么做呢?假如我们就将name声明为strong。NSString有个子类NSMutableString,我们是可以将NSMutableString对象赋值给NSString的,像这样:
NSMutableString *mutableName = [NSMutableString stringWithString:@"Mike"];
self.name = mutableName;
然而如果我们在后面的代码中修改了mutableName的值,name的值也会随之改变。这当然是不合理的,NSString的值应该是不变的。而copy的作用就是这个。通过copy方法,创建了一个新的值和mutableName相同的对象,所以mutableName的值改变并不会影响到name。
什么是可变拷贝mutableCopy
同样见名知意,就是拷贝出一个可变的对象出来。例如:
NSMutableString *mutableStr = [@"abc" mutableCopy];
通过对NSString进行mutableCopy而产生了一个NSMutableString。我见过一些人创建mutableString就是这样写的,但是从代码规范和效率的角度讲,这样做是不推荐的。
copy的妙用
copy方法除了可以对对象进行深拷贝以外还有个优点就是,相比于重新创建一个对象,copy的效率更高。例如要创建一百个MyClass对象,实例化一个对象然后使用copy方法的效率要比实例化一百次高得多。
网友评论