关于深复制与浅复制

转自“红黑联盟”,网址:http://www.2cto.com/kf/201405/302273.html

第一、复制对象的基本概念

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

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

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

第三、retain和copy的区别

    @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!");

    }

结果:

2014-05-19 10:58:22.639 objective[1095:303] the part is one
2014-05-19 10:58:22.641 objective[1095:303] the part is two
2014-05-19 10:58:22.641 objective[1095:303] the part is three
2014-05-19 10:58:22.641 objective[1095:303] the retaincount is 2
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返回一个可变对象的副本。

        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框架支持复制的类,默认是浅复制

        NSMutableArray *array=[[NSMutableArray alloc] init];
        for(int i=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);
        }
2013-09-30 17:28:01.492 FDAS[681:303] 地址为 0x1001081f0,引用计数是 1
2013-09-30 17:28:01.506 FDAS[681:303] 地址为 0x100108230,引用计数是 1
2013-09-30 17:28:01.506 FDAS[681:303] 地址为 0x100108240,引用计数是 1
2013-09-30 17:28:01.507 FDAS[681:303] 地址为 0x1001081f0,引用计数是 2
2013-09-30 17:28:01.507 FDAS[681:303] 地址为 0x100108230,引用计数是 2
2013-09-30 17:28:01.507 FDAS[681:303] 地址为 0x100108240,引用计数是 2

第五、对象的自定义拷贝

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

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

浅拷贝代码如下:

#import 

@interface Person : NSObject
@property(nonatomic,retain)NSString *name;
@property(nonatomic,retain)NSString *age;

@end
#import "Person.h"

@implementation Person

- (id)copyWithZone:(NSZone *)zone
{
   //实现自定义浅拷贝
    Person *person=[[self class] allocWithZone:zone];
    person.age=_age;
    person.name=_name;
    return person;
}
@end

main函数为:

    @autoreleasepool {

        Person *person=[[Person alloc] init];
        [email protected]"andy";
        [email protected]"20";

        Person *person2=[person copy];
        NSLog(@"person 地址为%p,person2地址为%p",person.name,person2.name);
    }

输出结果为:

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

深拷贝代码如下:

- (id)copyWithZone:(NSZone *)zone
{
   //实现自定义浅拷贝
    Person *person=[[self class] allocWithZone:zone];
    person.age=[_age copy];
    person.name=[_age copy];
    return person;
}

结果:

2013-09-30 17:55:13.603 FDAS[742:303] person 地址为0x1000022c8,person2地址为0x1000022e8
        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一个可变对象时,副本对象是不可变的。

关于深拷贝和浅拷贝:

第一、浅拷贝:

    Car *car=[[[self class] allocWithZone:zone] init];
    car.engine=_engine;
    car.name=_name;
    car.weight=_weight;
    return car;

测试代码:

 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:

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

第二、深拷贝:

- (id)copyWithZone:(NSZone *)zone {
    /***浅拷贝**/
    Car *car=[[[self class] 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;
    return car;
}

测试代码:

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代表一块内存空间

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

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

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

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

        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时,不管对象是否可变,都会实现深拷贝

        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相当于两个对象指向同一个指针

        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);

结果:

2013-12-28 20:13:02.915 copyDemo1[736:303] (
    one,
    two,
    three
)
2013-12-28 20:13:02.917 copyDemo1[736:303] the retaincount is 2
时间: 2024-10-08 13:11:12

关于深复制与浅复制的相关文章

iOS 集合的深复制与浅复制

概念 对象拷贝有两种方式:浅复制和深复制.顾名思义,浅复制,并不拷贝对象本身,仅仅是拷贝指向对象的指针:深复制是直接拷贝整个对象内存到另一块内存中. 一图以蔽之 再简单些说:浅复制就是指针拷贝:深复制就是内容拷贝. 集合的浅复制 (shallow copy) 集合的浅复制有非常多种方法.当你进行浅复制时,会向原始的集合发送retain消息,引用计数加1,同时指针被拷贝到新的集合. 现在让我们看一些浅复制的例子: NSArray *shallowCopyArray = [someArray cop

深复制与浅复制

概念 对象拷贝有两种方式:浅复制和深复制.顾名思义,浅复制,并不拷贝对象本身,仅仅是拷贝指向对象的指针:深复制是直接拷贝整个对象内存到另一块内存中. 一图以蔽之 再简单些说:浅复制就是指针拷贝:深复制就是内容拷贝. 集合的浅复制 (shallow copy) 集合的浅复制有非常多种方法.当你进行浅复制时,会向原始的集合发送retain消息,引用计数加1,同时指针被拷贝到新的集合. 现在让我们看一些浅复制的例子: NSArray *shallowCopyArray = [someArray cop

OC 中 的copy 功能 深复制 和 浅复制 的 区别

系统的类要是实现copy拷贝的功能,必须先签订拷贝NSCopying的协议,然后实现对应的方法 在.h文件中得@interface Boy : NSObject 的后面需要签订拷贝NSCopying的协议 例子: 在.h文件中 @interface Boy : NSObject<NSCopying> 1. Boy类使用copy的方法 例子: Boy *boy =[Boy boyWithName:@"zhangyangyang" hobby:@"wan"]

.NET中深复制与浅复制

概述: 在.NET里面,提供对象复制的功能,前提是实现ICloneable接口.ICloneable接口中有一个Clone方法, 可以在类中覆写实现自定义的拷贝方法.对象复制的实现方法有两种:深复制和浅复制. 深复制和浅复制: 浅复制,浅复制是指源对象与复制出来的对象共用一份实体,对其中任何一个对象的改动都会影响另外一个对象.相当于复制了指针. 深复制:指源对象与复制对象互相独立,为新对象重新分配了一段内存空间,并复制源对象的内容.其中任何一个对象的改动都不会对另外一个对象造成影响. 深浅复制与

C++学习基础七——深复制与浅复制

一.深复制与浅复制基本知识 深复制和浅复制,又称为深拷贝和浅拷贝. 深复制和浅复制的区别如下图1所示: 图1 图1表示的是,定义一个类CDemo,包含int a和char *str两个成员变量, 当深复制时,A中的指针str与B中的指针str指向不同的地址,只是地址所指向的数据相同. 当浅复制时,A中的指针str与B中的指针str指向相同的地址. 1.浅复制:如果我们自己不实现复制构造函数,则C++会自动合成一个复制构造函数,又称为浅复制构造函数. 2.深复制:如果使用指针或者系统资源(如数据库

python 字典深复制和浅复制

#!/usr/bin/python# -*- coding: UTF-8 -*- import copydict1 = {'user': 'vickey', 'num': [1, 2, 3],'age':{'a':'1','b':'2'}}dict2 = dict1 # 对原始数据的任何操作都会影响该复制# 先进行数据的浅复制和深复制操作dict3 = dict1.copy() # 浅复制: 一级为引用对象,二级为拷贝:原始数据的二级目录改变了,浅复制的数据的二级目录也会改变,但一级目录不变di

clone()方法、深复制和浅复制

clone方法 Java中没有明确提供指针的概念和用法,而实质上没个new语句返回的都是一个指针的引用,只不过在大部分情况下开发人员不需要关心如何去操作这个指针而已. 在实际编程中,经常会遇到从某个已有对象A创建出另一个与A具有相同状态的对象B,并且B的修改不会影响到A的情况,例如Prototype(原型)模式中,就需要clone一个对象实例. 仅仅通过简单的复制操作显然无法达到这个目的,而Java提供了一个简单有效的clone()方法来满足这个需求. Java中所有的类默认都继承自Object

实现 $.extend 的深复制和浅复制

$.extend 是jquery常用的一个方法,该方法通过传第一个布尔型参数可以指定为深复制还是浅复制,如何使用不在本文讨论. 先来理解下什么是深复制: var ob1 = {'name' : 'Jack' , 'child' : {'name' : 'Tom', 'age' : '7'}}; var ob2 = {'name' : 'Rose' , 'child' : {'name' : 'Mike'}}; 浅复制后的结果:{'name' : 'Jack' ,'child' : {'name'

iOS深复制和浅复制

1.copy关键字 1> 浅拷贝与深拷贝 浅拷贝就是对内存地址的复制,让目标对象指针和源对象指向同一片内存空间. 深拷贝是指拷贝对象的具体内容,而内存地址是自主分配的,拷贝结束之后,两个对象虽然存的值是相同的,但是内存地址不一样,两个对象也互不影响,互不干涉. 2> copy和mutableCopy copy:对于可变对象为深复制,引用计数不改变;对于不可变对象是浅复制,引用计数每次加一.始终返回一个不可变对象. mutableCopy:始终是深复制,引用计数不改变.始终返回一个可变对象. 3

(知其所以然 主题2)从底层分析OC中ARC和非ARC下深复制和浅复制

今天,在坊间听到有人在争论OC中关于NSString的深浅复制,听了下,感觉很有必要来一个分析总结,让我们从底层去了解OC中深浅复制的运作机制. 所谓copy就是在原有对象的基础上产生一个副本对象,遵循最关键的两点原则: 1. 改变原对象的属性和行为不会对副本对象产生任何影响 2. 改变副本对象的属性和行为不会对原对象产生任何影响 在理解了这一层之后,我们一起来研究下deep copy 和 shallow copy,因为苹果是一个非常注重性能的公司,所以拷贝在底层实现没那么简单: 以NSStri