深复制与浅复制

时间:2022-08-23 14:48:25

  深复制与浅复制 需要遵守NSCopying, NSMutableCopying 2个协议

什么是copy
Copy的字面意思是“复制”、“拷贝”,是一个产生副本的过程

常见的复制有:文件复制
作用:利用一个源文件产生一个副本文件
特点:
修改源文件的内容,不会影响副本文件
修改副本文件的内容,不会影响源文件

OC中的copy
作用:利用一个源对象产生一个副本对象
特点:
修改源对象的属性和行为,不会影响副本对象
修改副本对象的属性和行为,不会影响源对象

 

如何使用copy功能
一个对象可以调用copy或mutableCopy方法来创建一个副本对象
copy : 创建的是不可变副本(如NSString、NSArray、NSDictionary)
mutableCopy :创建的是可变副本(如NSMutableString、NSMutableArray、NSMutableDictionary)

使用copy功能的前提
copy : 需要遵守NSCopying协议,实现copyWithZone:方法
@protocol NSCopying
- (id)copyWithZone:(NSZone *)zone;
@end

mutableCopy : 需要遵守NSMutableCopying协议,实现mutableCopyWithZone:方法
@protocol NSMutableCopying
- (id)mutableCopyWithZone:(NSZone *)zone;
@end 

 

深复制(深拷贝,内容拷贝,deep copy)
源对象和副本对象是不同的两个对象
源对象引用计数器不变, 副本对象计数器为1(因为是新产生的)
本质是:产生了新的对象

浅复制(浅拷贝,指针拷贝,shallow copy)
源对象和副本对象是同一个对象
源对象(副本对象)引用计数器 + 1, 相当于做一次retain操作
本质是:没有产生新的对象

 深复制与浅复制

 

实例1 NSString和NSMutableString:

NSString *str1 = @"abc";
    NSString *str2 = @"abc";
    
    BOOL isEquals = str1==str2?YES:NO;
    NSLog(@"=%@=",isEquals?@"相同":@"不相同");
    
    NSString *str3 = [str1 copy];
    isEquals = str3==str2?YES:NO;
    NSLog(@"=%@=",isEquals?@"相同":@"不相同");
    
    NSMutableString *str4 = [str1 mutableCopy];
    isEquals = str4==str1?YES:NO;
    NSLog(@"=%@=",isEquals?@"相同":@"不相同");
    
    NSLog(@"-----------------------");
    
    NSString *str5 = @"abc";
    NSMutableString *str6 = [NSMutableString stringWithFormat:@"abc"];
    isEquals = str5==str6?YES:NO;
    NSLog(@"=%@=",isEquals?@"相同":@"不相同");
    
    NSString *str7 = [str6 copy];
    isEquals = str7==str2?YES:NO;
    NSLog(@"=%@=",isEquals?@"相同":@"不相同");
    
    NSMutableString *str8 = [str6 mutableCopy];
    isEquals = str8==str6?YES:NO;
    NSLog(@"=%@=",isEquals?@"相同":@"不相同");

 运行结果:

2015-01-01 14:48:07.742 深复制与浅复制[934:56160] =相同=
2015-01-01 14:48:07.743 深复制与浅复制[934:56160] =相同=
2015-01-01 14:48:07.743 深复制与浅复制[934:56160] =不相同=
2015-01-01 14:48:07.743 深复制与浅复制[934:56160] -----------------------
2015-01-01 14:48:07.744 深复制与浅复制[934:56160] =不相同=
2015-01-01 14:48:07.744 深复制与浅复制[934:56160] =不相同=
2015-01-01 14:48:07.744 深复制与浅复制[934:56160] =不相同=
Program ended with exit code: 0

 注意:NSString copy产生的不可变数据对象也是指向原对象,上面str1和str3

实例2 NSArray和NSMutableArray:

 NSArray *array1 = @[@1,@2,@3];
    NSArray *array2 = @[@1,@2,@3];
    
    BOOL isEquals = array1 == array2 ? YES:NO;
    NSLog(@"=%@=",isEquals?@"相同":@"不相同");
    
    NSArray *array3 = [array1 copy];
    isEquals = array3 == array1 ? YES:NO;
    NSLog(@"=%@=",isEquals?@"相同":@"不相同");

    NSMutableArray *array4 = [array1 mutableCopy];
    isEquals = array4 == array1 ? YES:NO;
    NSLog(@"=%@=",isEquals?@"相同":@"不相同");
//    NSLog(@"%@",array1);
//    NSLog(@"%@",array4);
    [array4 addObject:@4];
//    NSLog(@"%@",array1);
    NSLog(@"%@",array4);
    
    NSLog(@"--------------------------");
    
    NSMutableArray *array5 = [NSMutableArray arrayWithObjects:@1,@2,@3, nil];
  
    NSArray *array6 = [array5 copy];
    isEquals = array5 == array6 ? YES:NO;
    NSLog(@"=%@=",isEquals?@"相同":@"不相同");
    
    NSMutableArray *array8 = [array5 mutableCopy];
    isEquals = array5 == array8 ? YES:NO;
    NSLog(@"=%@=",isEquals?@"相同":@"不相同");
//    NSLog(@"%@",array8);
    [array8 addObject:@4];
//    NSLog(@"%@",array5);
    NSLog(@"%@",array8);

 运行结果:

2015-01-01 15:00:30.950 深复制与浅复制[980:59234] =不相同=
2015-01-01 15:00:30.951 深复制与浅复制[980:59234] =相同=
2015-01-01 15:00:30.951 深复制与浅复制[980:59234] =不相同=
2015-01-01 15:00:30.952 深复制与浅复制[980:59234] (
    1,
    2,
    3,
    4
)
2015-01-01 15:00:30.952 深复制与浅复制[980:59234] --------------------------
2015-01-01 15:00:30.952 深复制与浅复制[980:59234] =不相同=
2015-01-01 15:00:30.952 深复制与浅复制[980:59234] =不相同=
2015-01-01 15:00:30.952 深复制与浅复制[980:59234] (
    1,
    2,
    3,
    4
)
Program ended with exit code: 0

 注意:NSArray copy产生的不可变数据对象也是指向原对象,上面array1和array3

 

实例4 NSDictionary和NSMutableDictionary 跟上面情况一样:

 

实例5:测试不管产生可变还是不可变对象,数组中存储内容对象都还是指向同一份对象

@interface Person : NSObject //<NSCopying, NSMutableCopying>

@property (nonatomic,copy) NSString *name;
@property (nonatomic,assign) int age;

- (void)eat;

- (instancetype)initWithName:(NSString *)name age:(int)age;
+ (instancetype)personWithName:(NSString *)name age:(int)age;

@end

 

#import "Person.h"

@implementation Person

- (void)eat{
    NSLog(@"%s",__func__);
}

+ (instancetype)personWithName:(NSString *)name age:(int)age{
    return [[self alloc] initWithName:name age:age];
}

- (instancetype)initWithName:(NSString *)name age:(int)age{
    if (self == [super init]) {
        self.name = name;
        self.age = age;
    }
    return self;
}

- (NSString *)description{
    return [NSString stringWithFormat:@"name=%@ age=%d",_name,_age];
}

//- (id)copyWithZone:(NSZone *)zone{
//    Person *person = [[Person allocWithZone:zone] init];
//    person.name = [self.name copy];
//    person.age = self.age;
//    return person;
//}
//
//- (id)mutableCopyWithZone:(NSZone *)zone{
//    Person *person = [[Person allocWithZone:zone] init];
//    person.name = [self.name mutableCopy];
//    person.age = self.age;
//    return person;
//}

@end

 

Person *p1 = [Person personWithName:@"zhangsan" age:20];
    Person *p2 = [Person personWithName:@"lisi" age:21];
    Person *p3 = [Person personWithName:@"wangwu" age:22];
    
    NSMutableArray *array1 = [NSMutableArray arrayWithObjects:p1,p2,p3, nil];
    NSLog(@"%@",array1);
    p1.name = @"zhangsan111";
    NSLog(@"%@",array1);
    
    NSArray *array2 = [array1 copy];
    NSLog(@"%@",array2);
    
    BOOL isEquals = array1 == array2?YES:NO;
    NSLog(@"=%@=",isEquals?@"相同":@"不相同");
    
    isEquals = array1[0] == array2[0];
    NSLog(@"=%@=",isEquals?@"相同":@"不相同");

 运行结果:

2015-01-01 15:18:58.814 深复制与浅复制[1100:64607] (
    "name=zhangsan age=20",
    "name=lisi age=21",
    "name=wangwu age=22"
)
2015-01-01 15:18:58.815 深复制与浅复制[1100:64607] (
    "name=zhangsan111 age=20",
    "name=lisi age=21",
    "name=wangwu age=22"
)
2015-01-01 15:18:58.815 深复制与浅复制[1100:64607] (
    "name=zhangsan111 age=20",
    "name=lisi age=21",
    "name=wangwu age=22"
)
2015-01-01 15:18:58.816 深复制与浅复制[1100:64607] =不相同=
2015-01-01 15:18:58.816 深复制与浅复制[1100:64607] =相同=

 说明复制后2个数组中存储的内容对象是相同的