iOS深浅拷贝,看完就会

浅拷贝:只创建一个新的指针,指向原指针指向的内存
深拷贝:创建一个新的指针,并开辟新的内存空间,内容拷贝自原指针指向的内存,并指向它

假设我们要对一个不可变的对象进行不可变copy(原来的对象不可变,新对象也不可变)。就没必要给新对象新建一块内存,反正大家都不可以对这个对象进行改变,那都使用一个就可以。所以iOS系统规定浅拷贝引用计数器加1就行。而需要给新对象开闭内存空间的,就是深拷贝。
这里写图片描述

copy得到的类型一定是不可变的;mutableCopy得到的类型一定是可变的
使用mutable,都是深拷贝(不管是拷贝类型还是拷贝方法);但是copy也有深拷贝;

以下分类验证:

一. 对于不可变对象

//copy,       浅拷贝(指针复制)
//mutableCopy,深拷贝(对象复制 指针+内存),返回对象可变(产生新的可变对象)
- (void)imutableInstanceCopy
{
    NSString *string = @"Hello";

    //copy,浅拷贝(拷贝出一个新的指针,指向string指向的内存地址)
    NSString *stringCopy = [string copy];
    //mutableCopy,深拷贝(拷贝出一个新的指针,并且拷贝一份string指向的内存并指向它,不指向string指向的内存地址)
    NSMutableString *stringMutableCopy = [string mutableCopy];
    [stringMutableCopy appendString:@"!"];

    NSLog(@"string:     %@ , %p", string,string);
    NSLog(@"strongCopy: %@ , %p", stringCopy,stringCopy);
    NSLog(@"stringMCopy:%@ , %p", stringMutableCopy,stringMutableCopy);

    //结论://string与stringCopy的内存地址相同,俩不同的指针指向同一个地址;
           //string与stringMutableCopy的内存地址不同,分配了新的内存
}

对不可变对象:
2018-02-26 18:36:57.984922+0800 深浅拷贝[31542:2723909] string: Hello , 0x105820078
2018-02-26 18:36:57.985022+0800 深浅拷贝[31542:2723909] strongCopy: Hello , 0x105820078
2018-02-26 18:36:57.985113+0800 深浅拷贝[31542:2723909] stringMCopy:Hello! , 0x60400005b300

二、对可变对象复制,都是深拷贝,但是copy关键字返回的对象是不可变的

//copy,       深拷贝(对象复制),返回对象不可变
//mutableCopy,深拷贝(对象复制),返回对象可变
- (void)mutableInstanceCopy
{
    NSMutableString *mutableString = [NSMutableString stringWithString: @"Hello"];

    //copy 深拷贝,返回对象不可变
    id mutableStringCopy = [mutableString copy];
    //运行时,此句会报错,错误信息“Attempt to mutate immutable object with appendString:”
//    [mutableStringCopy appendString:@"~~~"];

    //mutableCopy 深拷贝,返回对象可变
    NSMutableString *mutableStringMutableCopy = [mutableString mutableCopy];
    [mutableStringMutableCopy appendString:@"!"];

    //内存地址都不同
    NSLog(@"mutableString:    %@ , %p", mutableString,mutableString);
    NSLog(@"mutableStringCopy:%@ , %p", mutableStringCopy,mutableStringCopy);
    NSLog(@"mutableStringMutableCopy:%@ , %p", mutableStringMutableCopy,mutableStringMutableCopy);
}

对可变对象:
2018-02-26 18:41:23.806579+0800 深浅拷贝[31596:2729403] mutableString: Hello , 0x60c00025e5a0
2018-02-26 18:41:23.806781+0800 深浅拷贝[31596:2729403] mutableStringCopy:Hello , 0xa00006f6c6c65485
2018-02-26 18:41:23.806883+0800 深浅拷贝[31596:2729403] mutableStringMutableCopy:Hello! , 0x60c00025e6c0

三、容器对象(NSArray,NAMutableArray;NSDictionary,NSMutableDictionary;NSSet集合)遵循非容器对象的拷贝原则

//注意容器里套可变对象的情况(容器内的元素都是浅拷贝)
//开发时注意,数组中都是模型时,拷贝后的数组中的模型还是原来数组的模型,一个变都改变
- (void)containerInstanceShallowCopy
{
    NSArray *array = [NSArray arrayWithObjects:[NSMutableString stringWithString:@"Welcome"],@"to",@"Xcode",nil];

    //未创建了新的容器,容器内的元素是指针赋值(浅拷贝)
    NSArray *arrayCopy = [array copy];
    //创建了新的容器,容器内的元素是指针赋值(浅拷贝)
    NSMutableArray *arrayMutableCopy = [array mutableCopy];

    NSLog(@"array:     %p", array);
    NSLog(@"arrayCopy: %p", arrayCopy);
    NSLog(@"arrayMutableCopy: %p", arrayMutableCopy);

    //容器内的对象是浅拷贝,即它们在内存中只有一份
    NSMutableString *testString = [array objectAtIndex:0];
    [testString appendString:@" you"];
    //三个数组的内容同时改变
    NSLog(@"array[0]: %@", array[0]);
    NSLog(@"arrayCopy[0]: %@", arrayCopy[0]);
    NSLog(@"arrayMutableCopy[0]: %@", arrayMutableCopy[0]);
}

对容器对象:
2018-02-26 18:44:28.818598+0800 深浅拷贝[31639:2733020] array: 0x604000445010
2018-02-26 18:44:28.818719+0800 深浅拷贝[31639:2733020] arrayCopy: 0x604000445010
2018-02-26 18:44:28.818797+0800 深浅拷贝[31639:2733020] arrayMutableCopy: 0x604000445a00
2018-02-26 18:44:28.818873+0800 深浅拷贝[31639:2733020] array[0]: Welcome you
2018-02-26 18:44:28.818926+0800 深浅拷贝[31639:2733020] arrayCopy[0]: Welcome you
2018-02-26 18:44:28.818998+0800 深浅拷贝[31639:2733020] arrayMutableCopy[0]: Welcome you

四、对象序列化,实现真正意义的拷贝(数组内的对象也实现深拷贝):

- (void)containerInstanceDeepCopy
{
    NSArray *array = [NSArray arrayWithObjects:[NSMutableString stringWithString:@"Welcome"],@"to",@"Xcode",nil];

    //数组内对象是指针复制
    NSArray *deepCopyArray = [[NSArray alloc] initWithArray:array];
    //真正意义上的深复制,数组内对象是对象复制
    NSArray *trueDeepCopyArray = [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:array]];

    NSLog(@"array: %p", array);
    NSLog(@"deepCopyArray: %p", deepCopyArray);
    NSLog(@"trueDeepCopyArray: %p", trueDeepCopyArray);

    //改变array的第一个元素
    [[array objectAtIndex:0] appendString:@" you"];

    //只影响deepCopyArray数组的第一个元素
    NSLog(@"array[0]: %@", array[0]);
    NSLog(@"arrayCopy[0]: %@", deepCopyArray[0]);
    //不影响trueDeepCopyArray数组的第一个元素,是真正意义上的深拷贝
    NSLog(@"arrayMutableCopy[0]: %@", trueDeepCopyArray[0]);
}

对象序列化:
2018-02-26 19:00:24.289068+0800 深浅拷贝[31729:2753480] array: 0x608000443f60
2018-02-26 19:00:24.289200+0800 深浅拷贝[31729:2753480] deepCopyArray: 0x608000444050
2018-02-26 19:00:24.289296+0800 深浅拷贝[31729:2753480] trueDeepCopyArray: 0x608000443570
2018-02-26 19:00:24.289390+0800 深浅拷贝[31729:2753480] array[0]: Welcome you
2018-02-26 19:00:24.289479+0800 深浅拷贝[31729:2753480] arrayCopy[0]: Welcome you
2018-02-26 19:00:24.289593+0800 深浅拷贝[31729:2753480] arrayMutableCopy[0]: Welcome

五、自定义对象拷贝:


Person.h ------------

@interface Person : NSObject<NSCopying,NSMutableCopying>
@property (nonatomic, strong) NSMutableString *name;//注意!!这里的修饰符不能用copy,否则深拷贝也会返回不可变
@property (nonatomic, copy) NSString *address;
@property (nonatomic, assign) NSInteger age;
@end

Person.m ------------

@implementation Person

- (instancetype)init
{
    self = [super init];
    if (self) {
        self.name = [[NSMutableString alloc]initWithString:@"原name"];
        self.address = @"原address";
        self.age = 0;
    }
    return self;
}

//浅拷贝实现- (id)copyWithZone:(NSZone *)zone
-(id)copyWithZone:(NSZone *)zone
{
    Person *p = [[self class]allocWithZone:zone];
    p.name    = [self.name copy];
    p.address = [self.address copy];

//    p.name = self.name ;
//    p.address = self.address ;

    p.age     = self.age;

    return p;
}

//深拷贝实现- (id)mutableCopyWithZone:(NSZone *)zone
-(id)mutableCopyWithZone:(NSZone *)zone
{
    Person *p = [[self class] allocWithZone:zone];
    p.name    = [self.name mutableCopy];
    p.address = [self.address mutableCopy];
    p.age     = self.age;

    return p;
}

@end
结尾总结几点深浅拷贝的应用:

1、@property (nonatomic, strong) NSMutableString *name;为什么不用copy修饰?

若用copy修饰这个可变字符串属性,当给name属性赋值时,setter方法会触发深拷贝,导致结果是name属性不再可变,因为可变字符串的copy返回不可变对象。

2、NSString类型的属性用copy,还是strong修饰?

@interface TestClass ()
@property (nonatomic, strong) NSString *strongString;
@property (nonatomic, copy)   NSString *copyedString;
@end

------

//这种情况下:
NSMutableString *muString = [NSMutableString stringWithFormat:@"abc”];
self.strongString = muString;
self.copyedString = muString;

如果是可变字符串,赋值给strongString时,strongString就直接指向了muString(默认浅拷贝copy),造成万一muString改变,self.strongString就会被改变的bug;
而用copy修饰的self.copyedString,会深拷贝一份新的可变字符串,和muString再无瓜葛~
所以若无上述情况下,strong用也未出错,但是最好用copy,严谨一点。

3.页面传参,传了个可变数组,要注意的地方:

//在页面1跳到页面2,正常传参~
ViewController2 *vc2 = [[ViewController2 alloc]init];
//注意这里需要mutableCopy来深拷贝一个新对象,若不用默认是copy,choiceArray就和页面1传过来的dataArray指向同一个内存,choiceArray改变的话,就会改变页面1的dataArray数组,造成数据错乱的莫名bug~
vc2.choiceArray = [self.dataArray mutableCopy];
[self.navigationController pushViewController:vc2 animated:YES];

孰能生巧,复习整理一下小知识点^_^

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值