深拷贝&浅拷贝
无论使用什么语言编程我们都必须考虑深拷贝和浅拷贝的问题,只是Objective-c提供了一个实现深拷贝的标准机制而已。所谓浅拷贝其实就是指针的赋值,例如:
NSString* str1 = @"Hello World!"; NSString* str2 = str1;
此时str1和str2同时指向了内存中的同一片区域,无论使用哪个指针对该区域进行了改动,使用另一个指针获取到的内容也会随之变化。这就是所谓的浅拷贝。而所谓的深拷贝是重新申请一块区域,重新建立一个对象,同时将原有对象的内容全部复制过来。例如:
NSString* str1 = @"Hello World!" NSString* str2 = [str1 copy];
此时,无论操作哪个指针对其内容进行修改,另外一个指针所指示的内容不会受到影响。这里多说一句,调用NSString的copy函数复制出来的对象实际和原有对象指向的是同一片区域。但是如果如果对其指向的内容进行修改的话,因为NSString属于不可改变(immutable)对象,所以系统会重新申请一片空间,写入修改后的内容返回给该指针。而另外一个指向原来区域的指针不受任何影响。如下:
int main(int argc, const char * argv[]) { @autoreleasepool { NSString* str = @"hello world"; NSString* str1 = [str copy]; NSLog(@"str:%p, str1:%p", str, str1); str = @"liyazhou"; NSLog(@"str:%@, str1:%@", str, str1); NSLog(@"str:%p, str1:%p", str, str1); } return 0; }
得到的结果是:
NSCopying&NSMutableCopying协议
之所以可以在Objective-c下使用copy和mutablecopy函数进行对象的拷贝是因为Objective-c实现了NSCopying和NSMutableCopying协议,这两个协议规定了对其所属对象进行复制的具体操作:
@protocol NSCopying - (id)copyWithZone:(nullable NSZone *)zone; @end @protocol NSMutableCopying - (id)mutableCopyWithZone:(nullable NSZone *)zone; @end
这两个协议分别声明了一个方法,而具体的复制操作就在这两个方法中实现。例如调用NSString的copy操作实际就是执行了NSString的copyWithZone函数。
对于常用的类型,这两个协议都已经实现,所以用户只需要调用copy和mutableCopy方法即可,但是对于自定义的类,要想使用copy方法就必须自己实现该协议。例如:
#import <Foundation/Foundation.h> @interface Person : NSObject<NSCopying> { } @property (nonatomic, strong) NSString* name; @property (nonatomic) int age; -(instancetype)init; -(id)copyWithZone:(NSZone *)zone; @end
#import "Person.h" @implementation Person -(instancetype)init { self = [super init]; if(self) { _name = @"李牙刷儿"; _age = 25; } return self; } -(id)copyWithZone:(NSZone *)zone { Person *p = [[Person allocWithZone:zone]init]; p.name = self.name; p.age = self.age; return p; } @end