iOS 深拷贝与浅拷贝的理解与实践

666 阅读4分钟

在开发过程中,一直对函数内部修改外部对象的知识抱有怀疑态度,不知道什么情况下可以修改,什么情况下又不可以修改,因此通过demo的方式进行了实践测试。

涉及的知识点:深拷贝、浅拷贝、可变对象、不可变对象、容器等。

浅拷贝就是拷贝后,并没有进行真正的复制,而是复制的对象和原对象都指向同一个地址,也就是同一片内存空间;

深拷贝是真正的复制了一份,复制的对象指向了新的地址,也就是不同的内存空间;

以下几个代表性的例子

字符串

NSString *str = @"字符串";
NSLog(@"方法调用前 str=%@,对象地址=%p,指针地址=%p \n",str,str,&str);
[self changeStrValue:str];
NSLog(@"方法调用后 str=%@,对象地址=%p,指针地址=%p \n",str,str,&str);

- (void)changeStrValue:(NSString *)string{
    NSLog(@"方法执行前 str=%@,对象地址=%p,指针地址=%p \n",string,string,&string);
    string = @"改变后的字符串";
    NSLog(@"方法执行后 str=%@,对象地址=%p,指针地址=%p \n",string,string,&string);
}

打印:

2021-10-19 方法调用前 str=字符串,对象地址=0x1010e6068,指针地址=0x7ffeeeb1a0f0 
2021-10-19 方法执行前 str=字符串,对象地址=0x1010e6068,指针地址=0x7ffeeeb1a0b8 
2021-10-19 方法执行后 str=改变后的字符串,对象地址=0x1010e61c8,指针地址=0x7ffeeeb1a0b8 
2021-10-19 方法调用后 str=字符串,对象地址=0x1010e6068,指针地址=0x7ffeeeb1a0f0 

数组

NSMutableArray *arr = [NSMutableArray arrayWithArray:@[@1,@2]];
NSLog(@"方法调用前 str=%@,对象地址=%p,指针地址=%p \n",arr,arr,&arr);
[self changeArray:arr];
NSLog(@"方法调用后 str=%@,对象地址=%p,指针地址=%p \n",arr,arr,&arr);
NSLog(@"%@",arr);

- (void)changeArray:(NSMutableArray *)arr{
    NSLog(@"方法执行前 str=%@,对象地址=%p,指针地址=%p \n",arr,arr,&arr);
    [arr addObject:@3];
    NSLog(@"方法执行后 str=%@,对象地址=%p,指针地址=%p \n",arr,arr,&arr);
}

打印:

2021-10-19 方法调用前 str=( 1, 2 ),对象地址=0x60000248cf00,指针地址=0x7ffeee6280e0 

2021-10-19 方法执行前 str=( 1, 2 ),对象地址=0x60000248cf00,指针地址=0x7ffeee628088 

2021-10-19 方法执行后 str=(  1, 2, 3 ),对象地址=0x60000248cf00,指针地址=0x7ffeee628088 

2021-10-19 方法调用后 str=( 1, 2, 3 ),对象地址=0x60000248cf00,指针地址=0x7ffeee6280e0 

2021-10-19  ( 1, 2, 3 )

自定义对象

@interface Model : NSObject

@property (nonatomic , strong) NSString  * name;
@property (nonatomic , assign) NSInteger    age;

@end
 Model *m = [[Model alloc] init];
 m.name = @"jim";
 m.age = 1;
 NSLog(@"方法调用前 m=%@,对象地址=%p,指针地址=%p \n",m,m,&m);
 [self changeModel:m];
 NSLog(@"方法调用前 m=%@,对象地址=%p,指针地址=%p \n",m,m,&m);

- (void)changeModel:(Model *)model{
    NSLog(@"方法执行前 str=%@,对象地址=%p,指针地址=%p \n",model,model,&model);
    model.age = 2;
    model.name = @"ddd";
    NSLog(@"方法执行后 str=%@,对象地址=%p,指针地址=%p \n",model,model,&model);
}

打印:

2021-10-19 方法调用前 m=<Model: 0x60000284cca0>,对象地址=0x60000284cca0,指针地址=0x7ffeebde50f8 

2021-10-19 方法执行前 str=<Model: 0x60000284cca0>,对象地址=0x60000284cca0,指针地址=0x7ffeebde50c8 

2021-10-19 方法执行后 str=<Model: 0x60000284cca0>,对象地址=0x60000284cca0,指针地址=0x7ffeebde50c8 

2021-10-19 方法调用前 m=<Model: 0x60000284cca0>,对象地址=0x60000284cca0,指针地址=0x7ffeebde50f8 

参考的网站:
深刻理解iOS中的“深拷贝”和“浅拷贝”

关于OC按引用传参的技巧

Objective-C中的值传递和引用传递