IOS开发复制的总结(深拷贝浅拷贝区别)

时间:2023-01-23 19:51:56
 1.复制可变字符串
        NSMutableString * city = [NSMutableString stringWithString:@"北京"];
        //复制可变副本
        NSMutableString * cityCopy = [city mutableCopy];
        //修改副本
        [cityCopy replaceCharactersInRange:NSMakeRange(0, 2) withString:@"临沧"];
        //输出看到原字符串没有改变 当前的改变
        NSLog(@"原来的city是%@,现在的cityCopy是%@",city,cityCopy);

 2.复制不可变字符串的可变副本
 NSString * str   =@"测试的字符串";
        NSMutableString * strCopy = [str mutableCopy];
        //增加字符串
        [strCopy appendString:@"再加一段字符串"];
        NSLog(@"strCopy是是%@",strCopy);
        //为可变字符串返回一个不可变副本
        NSMutableString * cityCopy2 = [city copy];
        //由于city是不可变的下面的代码是错误的
        [cityCopy2 appendString:@"这样是错的"];
报错信息
//        2015-05-05 17:19:37.988 copyDemo[424:303] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Attempt to mutate immutable object with appendString:'
//        *** First throw call stack:
     总结 复制的时候返回的字符串是否可变与原来的字符串或是复制时给予的类型没有关系。主要取决于调用了copy方法还是mutableCopy方法。

3.对象拷贝

对于自定义的对象我们需要实现NSCopying和NSMutableCopying
@interface Person : NSObject
@property(nonatomic,strong)NSMutableString *name;
@property(nonatomic,assign)int age;
@end
#import "Person.h"
@interface Person()<NSCopying>
@end
@implementation Person


- (id)copyWithZone:(NSZone *)zone{
    Person * person = [[[self class] allocWithZone:zone] init];
    person.name = self.name;
    person.age = self.age;
    return person;
}
@end
#import <Foundation/Foundation.h>
#import "Person.h"
int main(int argc, const char * argv[]) {
    @autoreleasepool {


        Person * person = [Person new];
        person.name = [NSMutableString stringWithString:@"小明"];
        person.age = 20;
        
        Person * personCopy = [person copy];//复制副本
        personCopy.name = [NSMutableString stringWithString:@"小强"];
        personCopy.age  =23;
        NSLog(@"person的名字是%@",person.name);
        NSLog(@"person的n年龄是%d",person.age);
        NSLog(@"personCopy的名字是%@",personCopy.name);
        NSLog(@"personCopy的年龄是%d",personCopy.age);


//        2015-05-05 17:38:43.980 copyDemo[531:303] person的名字是小明
//        2015-05-05 17:38:43.981 copyDemo[531:303] person的n年龄是20
//        2015-05-05 17:38:43.981 copyDemo[531:303] personCopy的名字是小强
//        2015-05-05 17:38:43.982 copyDemo[531:303] personCopy的年龄是23
    }
    return 0;
}

4.浅拷贝

其他不变修改main函数
  Person * person = [Person new];
        person.name = [NSMutableString stringWithString:@"小明"];
        person.age = 20;
        Person * personCopy = [person copy];//复制副本
        [personCopy.name replaceCharactersInRange:NSMakeRange(0,2) withString:@"变了嘛"];
        personCopy.age  =23;
        NSLog(@"person的名字是%@",person.name);
        NSLog(@"person的n年龄是%d",person.age);
        NSLog(@"personCopy的名字是%@",personCopy.name);
        NSLog(@"personCopy的年龄是%d",personCopy.age);
打印出来的是
2015-05-05 17:54:05.347 copyDemo[563:303] person的名字是变了嘛
2015-05-05 17:54:05.349 copyDemo[563:303] person的n年龄是20
2015-05-05 17:54:05.350 copyDemo[563:303] personCopy的名字是变了嘛

2015-05-05 17:54:05.350 copyDemo[563:303] personCopy的年龄是23

一开始我也很迷惑。差距只有一句代码而已。不过还是有差别的。
原因就在
    person.name = self.name;
    person.age = self.age;
    name是一个指针变量,存放的只是字符串地而已。所以说修改了拷贝的name,原来的name也会发生改变,使用personCopy.name = [NSMutableString stringWithString:@"小强"];这句代码的话其实是直接重新赋值,指向了另外一个字符串指针,所以拷贝的对象修改了。原来的并没有改变。但是并不代表拷贝的时候不指向一个字符串。只是后来被修改了。

5.深拷贝

将copyWithZone方法里面的修改

    person.name = [self.name mutableCopy];
    person.age = self.age;
这样就实现了深复制。
但是一般情况下,深复制难度比较大。尤其是有很多指针的时候,Fundation一般都是浅复制。

6.setetr方法的复制

修改如下代码
@property(nonatomic,copy)NSMutableString *name;
修改main
        Person * person = [Person new];
        person.name = [NSMutableString stringWithString:@"小明"];
        //下面这行代码会报错的。
        [person.name appendString:@"会报错了"];
name的属性使用了copy指示符的话其实相当于setNmame方法里面
- (void)setName(NSString *)name{
name = [name copy];
}
是对参数的一个不可变拷贝