在OC語法中,提供了Copy語法(Copy + MutableCopy)用於對象的拷貝。其中很容易混淆的是淺拷貝和深拷貝。
所謂淺拷貝,即是地址拷貝,並不產生新的對象,而是對原對象的引用計數值加1。而深拷貝,即是對象拷貝,產生新的對象副本,計數器為1。
下面通過一個例子來分析一下這個比較容易亂的Copy:
一、對於NSString/NSMutableString; NSArray/NSMutableArray... 這OC提供的類對象:
以NSString/NSMutableString為例:
對於copy,返回的一定是不可變類型;而mutableCopy,返回的一定是可變類型。
①對於 mutableCopy ,一定是深拷貝。
//對於 mutableCopy,都是深拷貝:對象的拷貝,產生新的對象
void strMutableCopy(){
NSString *str=[[NSString alloc]initWithFormat:@"abcd"];
// NSMutableString *str = [[NSMutableString alloc] initWithFormat:@"abcd"];
//產生了一個新的對象 計數器為1 源對象的計數器不變
NSMutableString *str2=[str mutableCopy];
// NSString *str2 = [str mutableCopy];
//輸出二者的地址,二者的地址是不同的
NSLog(@"str --> %p",str);
NSLog(@"str2 --> %p",str2);
}②對於 copy:
如果是 NSString ---> NSString;則是淺拷貝;如果是 NSMutableString ---> NSString;則是 深拷貝。
如果是 NSString 、NSMutableString ---> NSMutableString;則是深拷貝。
注:只有一種情況下是發生淺拷貝:不可變對象 復制到 不可變對象。
//淺拷貝:指針拷貝 不會產生新的對象,源對象計數器加1
void strCopy(){
NSString *str=[[NSString alloc]initWithFormat:@"abcd"];
//因為NSString對象本身就不可變,所以並沒產生新的對象,而是返回對象本身,會做一次retain操作,所以源對象也會retain
NSString *str2=[str copy];
//輸出二者的地址,二者的地址是相同的
NSLog(@"str --> %p",str);
NSLog(@"str2 --> %p",str2);
}例如:
//深拷貝
void mutableStrCopy(){
NSMutableString *str=[[NSMutableString alloc]initWithFormat:@"abcd"];
//會產生一個新的對象計數器1
NSString *str2=[str copy];
//輸出二者的地址,二者的地址是不同的
NSLog(@"str --> %p",str);
NSLog(@"str2 --> %p",str2);
}同理,對於自定義對象的mutableCopy:必須實現 NSMutableCopying 協議,重寫 mutableCopyWithZone 方法。
在NSCopying協議中,其實只有一個協議方法:
@protocol NSCopying - (id)copyWithZone:(NSZone *)zone; @end
在NSMutableCopying協議:
@protocol NSMutableCopying - (id)mutableCopyWithZone:(NSZone *)zone; @end
#import@interface Person : NSObject @property(nonatomic,assign)int age; @property(nonatomic,copy)NSString *name; -(instancetype)initWithAge:(int)age withName:(NSString*)name; @end
#import "Person.h"
@implementation Person
-(instancetype)initWithAge:(int)age withName:(NSString*)name{
self = [super init];
if (self) {
self.age = age;
self.name = name;
}
return self;
}
-(id)copyWithZone:(NSZone *)zone{
Person* person = [[[self class] allocWithZone:zone] initWithAge:self.age withName:self.name];
return person;
}
@endint main(int argc, const char * argv[])
{
@autoreleasepool {
Person *p1 = [[Person alloc] initWithAge:20 withName:@"Jack"];
Person *p2 = [p1 copy];
//輸出兩個 Person 對象的地址,二者是不同的
NSLog(@"p1 --> %p",p1);
NSLog(@"p2 --> %p",p2);
}
return 0;
}-(id)copyWithZone:(NSZone *)zone{
return self;
}這樣,輸出的兩個對象的地址就是相同的了。
下面了解一下關於如果某一個自定義類繼承了 這個Person類的情況。
如果某一個子類繼承了實現了NSCopying協議的基類,那麼該子類也是會自動繼承這個協議的方法。但是需要自己重新實現。
例如:有一個Student子類繼承了這個Person類:
#import#import "Person.h" @interface Student : Person @property(nonatomic,copy)NSString *school; -(instancetype)initWithAge:(int)age withName:(NSString *)name WithSchool:(NSString*)school; @end
#import "Student.h"
@implementation Student
-(instancetype)initWithAge:(int)age withName:(NSString *)name WithSchool:(NSString*)school{
self = [super initWithAge:age withName:name];
if (self) {
self.school = school;
}
return self;
}
-(id)copyWithZone:(NSZone *)zone{
Student *student = [super copyWithZone:zone];
student.school = self.school;
return student;
}
@end