iOS学习笔记07--深拷贝与浅拷贝

首先,我们应该知道:

copy: 获得不可变对象;
mutableCopy: 获得可变对象;
无论是深拷贝还是浅拷贝,以上都成立。

copy与retain的区别:

(1)copy是创建一个新对象,retain是创建一个指针,引用对象计数加1。Copy属性表示两个对象内容相同,新的对象retain为1 ,与旧有对象的引用计数无关,旧有对象没有变化。copy减少对象对上下文的依赖。

(2)retain属性表示两个对象地址相同(建立一个指针,指针拷贝),内容当然相同,这个对象的retain值+1也就是说,retain 是指针拷贝,copy 是内容拷贝。

不同对象的深复制和浅复制

1、对于非容器对象,如:NSString、NSNumber、NSMutableString等等
(1)如果是不可变对象,copy是指针复制(浅拷贝),mutableCopy是对象复制(深拷贝)。

//指针拷贝(浅拷贝)
NSString *string = @"this is copy test";
NSString *stringCopy = [string copy];
//对象拷贝(深拷贝)
NSString *string = @"this is copy test";
NSMutableString *stringMCopy = [string mutableCopy];

2)如果是可变对象,copy,mutableCopy两者都是对象复制(深复制);

//对象拷贝(深拷贝)
NSMutableString *string = [NSMutableString stringWithString:@"this is test"];
NSString *stringCopy = [string copy];
//对象拷贝(深拷贝)
NSMutableString *string = [NSMutableString stringWithString:@"this is test"];
NSMutableString *mStringCopy = [string mutableCopy];

2、对于容器对象,如NSArray 、NSDictionary、NSMutableArray、NSMutableDictionary等等

对于容器本身,非容器的情况也是适用的。需要探讨的是复制后容器内对象的变化。

(1)对于不可变对象

//指针拷贝(浅拷贝)
NSArray *array = [NSArray arrayWithObjects:@"a",@"b",@"c", nil];
NSArray *copyArray = [array copy];
//对象拷贝(深拷贝)。
NSArray *mCopyArray = [array mutableCopy];

(2)对于可变对象

//对象拷贝(深拷贝)
NSMutableArray *mArray = [NSMutableArray arrayWithObjects:@"a",@"b",@"c", nil];
NSArray *copyMArray = [mArray copy];

//对象拷贝(深拷贝)
NSArray *mCopyMArray = [mArray mutableCopy];

(3)无论容器做何种拷贝,无论容器是可变还是不可变,对于容器内对象,都是指针拷贝(浅拷贝)。如何判断容器内对象是指针拷贝?只要打印出地址值即可:

NSLog(@"%p",[array objectAtIndex:0]);       //0x96184
NSLog(@"%p",[copyArray objectAtIndex:0]);   //0x96184
NSLog(@"%p",[mCopyArray objectAtIndex:0]);  //0x96184
NSLog(@"%p",[mArray objectAtIndex:0]);      //0xaf134
NSLog(@"%p",[copyMArray objectAtIndex:0]);  //0xaf134
NSLog(@"%p",[mCopyMArray objectAtIndex:0]); //0xaf134

以上例子,说明容器内对象都为指针拷贝。当然,每次运行程序,地址值都是随机的。但是只要是指针拷贝,容器中的各个对象对应地址值都是一致,学过程序的各位大胸弟都是清楚的,这里不赘叙。

(4)如果真的需要对容器内对象做对象拷贝(深拷贝),有如下例子:

NSArray *arr = [NSArray arrayWithObjects:[NSMutableString stringWithString:@"a"],@"b",@"c" ,nil];
//方法一
NSArray *deepCopyArr = [[NSArray alloc]initWithArray:arr copyItems:YES];
//方法二
NSArray *trueDeepCopyArr = [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:arr]];

NSLog(@"%p",[arr objectAtIndex:0]);          //0x1663bb90

NSLog(@"%p",[deepCopyArr objectAtIndex:0]);     //0x1663ba50

NSLog(@"%p",[trueDeepCopyArr objectAtIndex:0]); //0x1663c410

NSLog(@"%p",[arr objectAtIndex:1]);             //0x7c144

NSLog(@"%p",[deepCopyArr objectAtIndex:1]);     //0x7c144

NSLog(@"%p",[trueDeepCopyArr objectAtIndex:1]); //0x1663c2f0

从以上例子可以看出,deepCopyArr不是真正的深拷贝,对于容器内对象,
比如[arr objectAtIndex:0],为可变对象,为对象拷贝(深拷贝)。
比如[arr objectAtIndex:1],为不可变对象,为指针拷贝(浅拷贝)。

而trueDeepCopyArr无论是容器内对象可变还是不可变,都为对象拷贝(深拷贝)。

为何是这样?对于不可变对象,如果拿到这个对象,却不能修改,所以只需要指针拷贝,即使能够对象拷贝,拿到的对象是一样的,没法修改。所以指针拷贝即可,无需对象拷贝,也就不是真正意义上 的深拷贝。

方法二,则实现完全的对象拷贝(深拷贝)。

3、自定义对象的拷贝
自定义对象需要遵循两个协议:NSCopying、NSMutableCopying
下面提供一个例子:

Person.h:

#import <UIKit/UIKit.h>

@interface Person : 

UIViewController<NSCopying,NSMutableCopying>

@property (nonatomic,retain)NSMutableString *name;

@property (nonatomic,retain)NSString *lolName;

@property (nonatomic)int age;

@end

Person.m:

#import "Person.h"

@implementation Person

-(id)init{
    self = [super init];
    if (self) {
        self.name = [[NSMutableString alloc]init];
        self.lolName = [[NSString alloc]init];
        self.age = 1;
    }
    return self;
}


-(id)copyWithZone:(NSZone *)zone{
    Person *copyPerson = [[self.class allocWithZone:zone]init];
    copyPerson.name = self.name;
    copyPerson.lolName = self.lolName;
    copyPerson.age = self.age;
    return copyPerson;
}

-(id)mutableCopyWithZone:(NSZone *)zone{
    Person *copyPerson = [[self.class allocWithZone:zone]init];
    copyPerson.name = [_name mutableCopy];
    copyPerson.lolName = [_lolName copy];
    copyPerson.age = _age;
    return copyPerson;

}

@end

测试代码:

Person *myself = [[Person alloc]init];
[myself.name appendString:@"mk"];
myself.lolName = @"cleanlove";
myself.age = 24;
NSLog(@"原装:%p",myself);//0x15632a70

Person *copyMyself = [myself copy];
NSLog(@"复制:%p",copyMyself);//0x1553d730

Person *copyMyself2 = [myself mutableCopy];
NSLog(@"复制:%p",copyMyself2);//0x1553dcf0

从以上例子可以看出,对于自定义对象的copy和mutableCopy,均为对象拷贝(深拷贝)。而对于对象中的属性是何种拷贝,则需要根据以上第1点,对于可变对象、不可变对象进行判断。

ps:

深拷贝(对象拷贝、深复制)
浅拷贝(指针拷贝、浅复制)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值