copy深拷贝和浅拷贝的理解和使用

来源:互联网 发布:发票抵扣网络认证系统 编辑:程序博客网 时间:2024/04/30 04:55

概念:

        复制一个对象为副本,开辟一块新的内存来存储副本对象。

        如果一个对象想具备复制的功能,必须实现协议和协议


1 深复制:内容拷贝,源对象和副本对象指的是两个不同的对象,源对象引用计数器不变,副本对象引用计数器为1

2 浅复制:指针拷贝,源对象和副本对象指的都是同一个对象,对象引用计数器+1,相当于retain

3 只有不可变对象创建不可变副本(copy)才是浅复制,其它的都是深复制


4.ios中哪些可变哪些不可变:

NSObject自带的常用的对象有:NSNumber、NSString、NSArray、NSDictionary、NSMutableArray、NSMutableDictionay、NSMutableString,copy产生的对象时不可变的,mutableCopy产生的对象时可变的


他们之间的一些区别:

第一、retain和copy的区别


1
2
3
4
5
6
7
8
9
10
11
12
13
@autoreleasepool{
    NSMutableArray *array=[NSMutableArray arrayWithObjects:@"one",@"two",@"three",@"four",nil];
    NSMutableArray *retainArray=[array retain];
    [retainArray removeLastObject];
    for(NSString *str in array)
    {
        NSLog(@"the part is %@",str);
    }
    NSLog(@"the retaincount is %ld",[retainArray retainCount]);
    // insert code here...
    NSLog(@"Hello, World!");
     
}

结果:


1
2
3
4
2014-05-1910:58:22.639objective[1095:303] the part is one
2014-05-1910:58:22.641objective[1095:303] the part is two
2014-05-1910:58:22.641objective[1095:303] the part is three
2014-05-1910:58:22.641objective[1095:303] the retaincount is2

1
2
3
4
5
6
7
8
NSMutableArray *array=[NSMutableArray arrayWithObjects:@"one",@"two",@"three",@"four",nil];
        NSMutableArray *retainArray=[array mutableCopy];
        [retainArray removeLastObject];
        for(NSString *str in array)
        {
            NSLog(@"the part is %@",str);
        }
        NSLog(@"the retaincount is %ld",[retainArray retainCount]);


结果

2014-05-19 10:59:03.826 objective[1104:303] the part is one

2014-05-19 10:59:03.828 objective[1104:303] the part is two

2014-05-19 10:59:03.828 objective[1104:303] the part is three

2014-05-19 10:59:03.829 objective[1104:303] the part is four

2014-05-19 10:59:03.829 objective[1104:303] the retaincount is 1


第二、COPY和MutableCopy的区别

COPY 返回一个不可变对象的副本,MutalbeCopy返回一个可变对象的副本。


1
2
3
4
5
6
7
NSArray *array=[NSArray arrayWithObjects:@"one",@"two", nil];
NSMutableArray *array1=[array copy];
[array1 addObject:@"three"]; //error
NSMutableArray *array2=[array mutableCopy];
[array2 addObject:@"three"]; //right
// insert code here...
NSLog(@"Hello, World!");

第三、浅copy和深copy

浅复制尽复制对象本身,对象里的属性、包含的对象不做复制

深复制复制全部,包括对象的属性和其他对象

Foundation框架支持复制的类,默认是浅复制


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
NSMutableArray *array=[[NSMutableArray alloc] init];
for(inti=0;i<3;i++)
{
    NSObject *obj=[[NSObject alloc] init];
    [array addObject:obj];
    [obj release];
}
for(NSObject *obj1 in array)
{
    NSLog(@"地址为 %p,引用计数是 %ld",obj1,obj1.retainCount);
}
NSMutableArray *array2=[array copy];
for(NSObject *obj2 in array2)
{
    NSLog(@"地址为 %p,引用计数是 %ld",obj2,obj2.retainCount);
}


1
2
3
4
5
6
2013-09-3017:28:01.492FDAS[681:303] 地址为0x1001081f0,引用计数是1
2013-09-3017:28:01.506FDAS[681:303] 地址为0x100108230,引用计数是1
2013-09-3017:28:01.506FDAS[681:303] 地址为0x100108240,引用计数是1
2013-09-3017:28:01.507FDAS[681:303] 地址为0x1001081f0,引用计数是2
2013-09-3017:28:01.507FDAS[681:303] 地址为0x100108230,引用计数是2
2013-09-3017:28:01.507FDAS[681:303] 地址为0x100108240,引用计数是2

第五、对象的自定义拷贝

对象拥有复制特性,必须实现NSCopying,NSMutableCopying协议,实现该协议的copyWithZone方法和mutableCopyWithZone方法

深拷贝和浅拷贝的区别就在于copyWithZone方法的实现,

浅拷贝代码如下:


1
2
3
4
5
6
7
8
#import<foundation foundation.h="">
 
@interfacePerson : NSObject<nscopying>
@property(nonatomic,retain)NSString *name;
@property(nonatomic,retain)NSString *age;
 
@end
</nscopying></foundation>


1
2
3
4
5
6
7
8
9
10
11
12
13
#import"Person.h"
 
@implementationPerson
 
- (id)copyWithZone:(NSZone *)zone
{
   //实现自定义浅拷贝
    Person *person=[[selfclass] allocWithZone:zone];
    person.age=_age;
    person.name=_name;
    returnperson;
}
@end

main函数为:

1
2
3
4
5
6
7
8
9
@autoreleasepool{
     
    Person *person=[[Person alloc] init];
    person.name=@"andy";
    person.age=@"20";
     
    Person *person2=[person copy];
    NSLog(@"person 地址为%p,person2地址为%p",person.name,person2.name);
}
输出结果为:

1
2013-09-3017:48:41.007FDAS[732:303] person 地址为0x1000022c8,person2地址为0x1000022c8

深拷贝代码如下:

1
2
3
4
5
6
7
8
- (id)copyWithZone:(NSZone *)zone
{
   //实现自定义浅拷贝
    Person *person=[[selfclass] allocWithZone:zone];
    person.age=[_age copy];
    person.name=[_age copy];
    returnperson;
}

结果:


1
2013-09-3017:55:13.603FDAS[742:303] person 地址为0x1000022c8,person2地址为0x1000022e8


1
2
3
4
NSArray *arr=[NSArray arrayWithObjects:@"one",@"two",nil];
NSArray *arr2=[arr copy];
NSLog(@"the dress of arr is %p the dress of arr2 is %p",arr,arr2);
NSLog(@"the retainCount is %ld",arr.retainCount);

执行结果为:

2013-09-30 18:01:01.394 FDAS[787:303] the dress of arr is 0x100108320 the dress of arr2 is 0x100108320

2013-09-30 18:01:01.396 FDAS[787:303] the retainCount is 2


结果是一样的,是因为Foundation对于不可变复制对象而言,copy方法做了优化,相当于retain,故retaincount变成2.

相当于 在copyWithZone方法中:return [self retain];

第四、copy、mutableCopy和retain之间的关系

在Foundation对象中,copy是一个不可变的对象时,作用相当于retain

当使用mutableCopy时,不管源对象是否可变,副本是可变的,并且实现真正意义上的copy

当我们使用copy一个可变对象时,副本对象是不可变的。


关于深拷贝和浅拷贝:

第一、浅拷贝:


1
2
3
4
5
Car *car=[[[selfclass] allocWithZone:zone] init];
car.engine=_engine;
car.name=_name;
car.weight=_weight;
returncar;

测试代码:


1
2
3
4
5
6
7
8
9
10
11
Car *car = [[Car alloc] init];
       Engine *engine = [[Engine alloc] init];
       car.engine = engine;
       [engine release];
       //NSLog(@"engine retaincount is %lu",[engine retainCount]);
       car.name = @"奥迪";
       car.weight =@1000;
 
       Car *car2=[car copy];
      // NSLog(@"car2 retaincount is %lu",[car2 retainCount]);
       NSLog(@"car %@,car2:%@",car.engine,car2.engine);

输出结果:

car ,car2:

可以看出浅复制只是复制指针,并没有创建新的内存空间

第二、深拷贝:


1
2
3
4
5
6
7
8
9
10
11
12
13
- (id)copyWithZone:(NSZone *)zone {
    /***浅拷贝**/
    Car *car=[[[selfclass] allocWithZone:zone] init];
    Engine *engineCopy=[[_engine copy] autorelease];
    car.engine=engineCopy;
     
    NSString *namecopy=[[_name copy] autorelease];
    car.name=namecopy;
     
    NSNumber *weightcopy=[[_weight copy] autorelease];
    car.weight=weightcopy;
    returncar;
}

测试代码:

1
2
3
4
5
6
7
8
9
10
11
Car *car = [[Car alloc] init];
        Engine *engine = [[Engine alloc] init];
        car.engine = engine;
        [engine release];
        //NSLog(@"engine retaincount is %lu",[engine retainCount]);
        car.name = @"奥迪";
        car.weight =@1000;
 
        Car *car2=[car copy];
       // NSLog(@"car2 retaincount is %lu",[car2 retainCount]);
        NSLog(@"car %@,car2:%@",car.engine,car2.engine);

结果:

car ,car2:

开辟了新的空间,zone代表一块内存空间

1
Car *car=[[[self class] allocWithZone:zone] init];

注意上述代码用的是【self class】,而不是car,因为如果是用car,那么car的子类在调用此方法去实现copy协议时,就会出现内存问题

另外,当子类继承了父类时,他继承了父类的一切属性,包括要实现的协议

第三、NSFoundation,当我们copy的时一个不可变对象时,默认的copy都是浅拷贝,相当于retain


1
2
3
4
5
NSArray *array =[NSArray arrayWithObjects:@"one",@"two",@"three", nil];
NSArray *array1 = [array copy];
NSLog(@"%p",array);
NSLog(@"%p",array1);
NSLog(@"the retaincount is %lu",[array retainCount]);

输出结果:

copyDemo1[673:303] 0x10010a5d0

2013-12-28 20:01:10.969 copyDemo1[673:303] 0x10010a5d0

2013-12-28 20:01:10.969 copyDemo1[673:303] the retaincount is 2

注意retaincount会增加

当使用mutableCopy时,不管对象是否可变,都会实现深拷贝


1
2
3
4
5
NSArray *array =[NSArray arrayWithObjects:@"one",@"two",@"three", nil];
NSMutableArray *array1 = [array mutableCopy];
NSLog(@"%p",array);
NSLog(@"%p",array1);
NSLog(@"the retaincount is %lu",[array retainCount]);

结果:

copyDemo1[695:303] 0x10010a5d0

2013-12-28 20:07:08.570 copyDemo1[695:303] 0x10010b260

2013-12-28 20:07:08.570 copyDemo1[695:303] the retaincount is 1


第四、retain相当于两个对象指向同一个指针

1
2
3
4
5
NSMutableArray *array1 = [[NSMutableArray alloc] initWithObjects:@"one",@"two",@"three",@"foure", nil];
NSMutableArray *array2 = [array1 retain];
[array2 removeLastObject];
NSLog(@"%@",array1);
NSLog(@"the retaincount is %ld",array2.retainCount);
结果:

1
2
3
4
5
6
2013-12-2820:13:02.915copyDemo1[736:303] (
    one,
    two,
    three
)
2013-12-2820:13:02.917copyDemo1[736:303] the retaincount is2








1 0
原创粉丝点击