概述


  • 拷贝:复制一个与源对象内容相同的对象
  • 实现拷贝,需要遵守以下两个协议
    • NSCopying
    • NSMutableCopying
  • 拷贝返回对象的种类
    • 可变,mutableCopy消息返回的对象
    • 不可变,copy消息返回的对象
  • 拷贝的种类
    • 浅拷贝,只是复制了一个指向源对象的指针,未创建对象,未分配内存
    • 深拷贝,复制了源对象,创建了新对象,分配了内存
  • 注意
    • 系统对容器类的对象与非容器类的对象的内存处理是不同的,即当一个没有被其他对象强引用的对象从容器中移除后,该对象就销毁

Copy与Retain


  • copy

    • 是创建一个新的对象,内容拷贝
    • copy表示的是两个对象的内容相同, 新对象的引用计数为1
    • 与旧对象的引用计数无关,就对象没有变化
    • copy减少了对象对上下文的
  • retain
    • 创建的是一个指针,指针拷贝
    • 对象地址相同,内容固然相同
    • 对象的引用计数+1

不同对象的拷贝行为


  • 非容器对象(如NSString))

    • 对于不可变对象

      • 规则

        • copy,浅拷贝(指针复制)
        • mutableCopy,深拷贝(对象复制),返回对象可变(产生新的 可变对象)
      • 示例

        - (void)imutableInstanceCopy
        {
        NSString *string = @"Welcome to Xcode"; //copy,浅拷贝
        NSString *stringCopy = [string copy];
        //mutableCopy,返回的对象可变
        NSMutableString *stringMutableCopy = [string mutableCopy];
        [stringMutableCopy appendString:@"!"]; //string与stringCopy的内存地址相同
        NSLog(@"string: %p", string);
        NSLog(@"strongCopy: %p", stringCopy); //string与stringMutableCopy的内存地址不同,分配了新的内存
        NSLog(@"stringMCopy:%p", stringMutableCopy);
        }
    • 对于可变对象
      • 规则

        • copy,深拷贝(对象复制),返回对象不可变
        • mutableCopy,深拷贝(对象复制)
      • 示例

        - (void)mutableInstanceCopy
        {
        NSMutableString *mutableString = [NSMutableString stringWithString: @"Welcome to Xcode"]; //深拷贝,返回对象不可变
        NSString *stringCopy = [mutableString copy];
        NSMutableString *mutableStringCopy = [mutableString copy];
        //运行时,此句会报错,错误信息“Attempt to mutate immutable object with appendString:”
        [mutableStringCopy appendString:@"~~~"]; //深拷贝,返回对象可变
        NSMutableString *stringMutableCopy = [mutableString mutableCopy];
        [stringMutableCopy appendString:@"!"]; //三者与mutableString的内存地址都不同
        NSLog(@"mutableString: %p", mutableString);
        NSLog(@"string: %p", stringCopy);
        NSLog(@"mutableStringCopy: %p", mutableStringCopy);
        NSLog(@"stringMutbleCopy:%p", stringMutableCopy);
        }
  • 容器对象(NSArray

    • 遵循非容器对象的拷贝原则

    • 注意

      • 容器内的元素是指针赋值(浅拷贝)

      • 示例

        - (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]);
        }
    • 实现真正意义上的深复制

      - (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]);
      }
  • 自定义对象

    • 在定义对象要实现拷贝,需要遵守NSCoping与NSMutableCoping协议,并实现以下方法

      • - (id)copyWithZone:(NSZone *)zone,可变拷贝
      • - (id)mutableCopyWithZone:(NSZone *)zone,不可变拷贝
    • 示例(自定对象Person的拷贝)
      • 遵守协议,设置成员属性

        @interface Person : NSObject <NSCopying, NSMutableCopying>
        /**姓名*/
        @property (nonatomic, copy) NSMutableString *name;
        /**地址*/
        @property (nonatomic, copy) NSString *address;
        /**年龄*/
        @property (nonatomic, assign) NSInteger age;
        @end
      • 重写初始化方法

        - (instancetype)init
        {
        if (self = [super init])
        {
        self.name = [[NSMutableString alloc] initWithString:@"XiaoYaowang"];
        self.address = @"世俗孤岛";
        self.age = 3;
        }
        return self;
        }
      • 实现- (id)copyWithZone:(NSZone *)zone

        - (id)copyWithZone:(NSZone *)zone
        {
        Person *p = [[[self class] allocWithZone:zone] init];
        p.name = [self.name copy];
        p.address = [self.address copy];
        p.age = self.age; return p;
        }
      • 实现- (id)mutableCopyWithZone:(NSZone *)zone

        - (id)mutableCopyWithZone:(NSZone *)zone
        {
        Person *p = [[[self class] allocWithZone:zone] init];
        //注意,此处是mutableCopy方法
        p.name = [self.name mutableCopy];
        p.address = [self.address copy];
        p.age = self.age; return p;
        }

OC语言-08-深拷贝与浅拷贝详解(示例)的更多相关文章

  1. OC细节 - 1.深拷贝与浅拷贝详解

    概述 拷贝:复制一个与源对象内容相同的对象 实现拷贝,需要遵守以下两个协议 NSCopying NSMutableCopying 拷贝返回对象的种类 可变,mutableCopy消息返回的对象 不可变 ...

  2. 【转】 c++拷贝构造函数(深拷贝,浅拷贝)详解

     c++拷贝构造函数(深拷贝,浅拷贝)详解 2013-11-05 20:30:29 分类: C/C++ 原文地址:http://blog.chinaunix.net/uid-28977986-id-3 ...

  3. 【C++】拷贝构造函数(深拷贝,浅拷贝)详解

    一.什么是拷贝构造函数  首先对于普通类型的对象来说,它们之间的复制是很简单的,例如: ; int b = a; 而类对象与普通对象不同,类对象内部结构一般较为复杂,存在各种成员变量. 下面看一个类对 ...

  4. **Python中的深拷贝和浅拷贝详解

    Python中的深拷贝和浅拷贝详解   这篇文章主要介绍了Python中的深拷贝和浅拷贝详解,本文讲解了变量-对象-引用.可变对象-不可变对象.拷贝等内容.   要说清楚Python中的深浅拷贝,需要 ...

  5. javascript实现引用数据类型的深拷贝和浅拷贝详解

    关于引用类型值的详解,请看另一篇随笔 https://www.cnblogs.com/jinbang/p/10346584.html 深拷贝和浅拷贝,也就是引用数据类型栈和堆的知识点.深浅拷贝的原型都 ...

  6. c++拷贝构造函数(深拷贝,浅拷贝)详解

    一.什么是拷贝构造函数      首先对于普通类型的对象来说,它们之间的复制是很简单的,例如: ; int b=a;   而类对象与普通对象不同,类对象内部结构一般较为复杂,存在各种成员变量.  下面 ...

  7. python的拷贝方式以及深拷贝,浅拷贝详解

    python的拷贝方法有:切片方法, 工厂方法, 深拷贝方法, 浅拷贝方法等. 几种方法都可以实现拷贝操作, 具体区别在于两点:1.代码写法不同. 2.内存地址引用不同 代码演示: import co ...

  8. C++ 深拷贝和浅拷贝详解

    前言 在对象拷贝过程中,如果没有自定义拷贝构造函数,系统会提供一个缺省的拷贝构造函数,缺省的拷贝构造函数对于基本类型的成员变量,按字节复制,对于类类型成员变量,调用其相应类型的拷贝构造函数. 位拷贝( ...

  9. Go语言Slice作为函数参数详解

    Go语言Slice作为函数参数详解 前言 首先要明确Go语言中实质只有值传递,引用传递和指针传递是相对于参数类型来说. 个人认为上诉的结论不对,把引用类型看做对指针的封装,一般封装为结构体,结构体是值 ...

随机推荐

  1. 红黑树(五)之 Java的实现

    概要 前面分别介绍红黑树的理论知识.红黑树的C语言和C++的实现.本章介绍红黑树的Java实现,若读者对红黑树的理论知识不熟悉,建立先学习红黑树的理论知识,再来学习本章.还是那句老话,红黑树的C/C+ ...

  2. Java 集合系列09之 Map架构

    概要 前面,我们已经系统的对List进行了学习.接下来,我们先学习Map,然后再学习Set:因为Set的实现类都是基于Map来实现的(如,HashSet是通过HashMap实现的,TreeSet是通过 ...

  3. Java 时间日期系列目录

    下面是Java的时间和日期相关文章目录: 01. Java Calendar,Date,DateFormat,TimeZone,Locale等时间相关内容的认知和使用(1) Calendar 02.  ...

  4. Android 布局之TableLayout

    Android 布局之TableLayout 1 TableLayout简介 TableLayout是表格布局.TableLayout 可设置的属性包括全局属性及单元格属性. 1.1 全局属性 有以下 ...

  5. Understanding CMS GC Logs--转载

    原文地址:https://blogs.oracle.com/poonam/entry/understanding_cms_gc_logs Understanding CMS GC Logs By Po ...

  6. 使用命令行备份指定文件夹并保留最新N份

    客户需要对网站进行定期备份,并保留最近30天的文件,编写后以下脚本,通过Windows的任务计划进行调度 对比手工和任务计划调度运行情况来看,手工运行中可直接调用RAR.exe和网络进行传输,但是任务 ...

  7. 【Java】一次SpringMVC+ Mybatis 配置多数据源经历

    需求 现在在维护的是学校的一款信息服务APP的后台,最近要开发一些新功能,其中一个就是加入学校电影院的在线购票.在线购票实际上已经有一套系统了,但是是外包给别人开发的,我们拿不到代码只能拿到数据库,并 ...

  8. CentOS6.4安装包初识

    LiveCD 一般用来修复系统使用,有容量很小,不用安装,可以自启动等特性.bin DVD也具有同 样的功能,但是体积较大,所以会有live DVD. LiveDVD 与LiveCD 相同是不需要安装 ...

  9. 开放产品开发(OPD):产品负责人的工作原则和方法

    月26日我将在2014 WOT全球软件技术峰会做相关的一个主题演讲[产品负责人的工作原则和方法],个原则和相应的一些方法. 以下是本次分享内容: 完整版如下,如果你喜欢想下载的话,点击 http:// ...

  10. Action接收页面传来的参数方法

    接收页面传来的参数方法 1.第一种:在action中设置相应的变量 在相应的action中设置与将要传进来的参数名相同的变量 eg: 页面传给后台两个参数 name=chance & age ...