在前一篇文章中我们说到了如何解决对象的循环引用问题:http://blog.csdn.net/jiangwei0910410003/article/details/41926369,这一篇文章我们就来介绍一下OC中的对象拷贝概念,这个对于面向对象语言中都会有这种的问题,只是不同的语言有不同的解决方式:C++中有拷贝构造函数,Java中需要实现Cloneable接口,在clone方法中进行操作。但是不过OC更偏向于Java这种方式,OC中如果一个对象需要被拷贝,他需要实现协议:

<NSCopying>、<NSMutableCopying>

从名字上我们可以看到,一个协议是用于不可变对象的,一个协议适用于可变对象的

首先来介绍一下对象的拷贝的概念吧:

为什么要由对象的拷贝这么一个概念呢?看一个场景:假如现在一个对象中又一个数组对象,现在我们生成一个对象,同时将这个对象赋值给另外一个对象,那么现在问题是这两个对象中的数组对象是同一个,那么如果一个对象中去修改这个数值中的内容,另外一个对象中的数组内容也会被修改,相当于这个数组对象是共享的,当然我们有时候是不希望这种形式的出现的,这时候我们就出现了对象的拷贝。

具体来看一个例子吧

一、系统类对象的拷贝

//
//  main.m
//  30_CopyObject
//
//  Created by jiangwei on 14-10-13.
//  Copyright (c) 2014年 jiangwei. All rights reserved.
//#import <Foundation/Foundation.h>/***/
int main(int argc, const char * argv[]) {@autoreleasepool {//对象具备拷贝功能,必须实现如下协议//<NSCopying>、<NSMutableCopying>//copy方法返回的是一个不可变对象,mutableCopy方法返回的是一个可变对象/*NSMutableArray *array1 = [NSMutableArray arrayWithObjects:@"one",@"two",nil];NSMutableArray *array2 = [array1 retain];//retain只是引用计数+1,没有创建新的对象//array1与array2指针相同,指向同一个对象if(array1 == array2){NSLog(@"array1 == array2");NSLog(@"array1的引用计数:%ld",array1.retainCount);}*/NSMutableArray *array1 = [NSMutableArray arrayWithObjects:@"one",@"two",nil];//复制对象,创建一个新的副本对象//这里使用copy方法复制,返回的是一个不可变数组,但是用一个可变数组来声明,但是我们关心的是指针的的内容,而不是类型//所以array2的真实类型还是不可变类型的NSMutableArray *array2 = [array1 copy];//array2计数为:1,因为是新创建出来的对象//使用mutableCopy方法,返回的就是可变数组//当然这种方法只针对于那些有可变对象之分有用,对于其他的对象这个方法和copy方法的效果是一样的NSMutableArray *array3 = [array1 mutableCopy];if(array1 != array2){NSLog(@"array1 != array2");NSLog(@"array1的引用计数:%ld",array1.retainCount);NSLog(@"array2的引用计数:%ld",array2.retainCount);}[array2 release];[array1 release];}return 0;
}

我们看到,NSMutableArray有一个mutableCopy方法,这样返回的一个数组对象就是一个拷贝对象了。

但是这里需要注意的是:

copy方法和mutableCopy方法的区别

这两个方法的区别只在于那些有可变对象和不可变对象之分的对象上,对于没有这种区分的对象来说,这两个方法的效果是一样的。

[不可变对象 copy]是假拷贝,等价于[不可变对象 retain]

[不可变对象 mutableCopy是真拷贝

二、深拷贝和浅拷贝

在拷贝对象中也是有深拷贝和浅拷贝之分的

浅拷贝:只拷贝所有属性对象的指针

深拷贝:拷贝属性对象的内容

看个例子:

Person.h

//
//  Person.h
//  31_DeepCopy
//
//  Created by jiangwei on 14-10-13.
//  Copyright (c) 2014年 jiangwei. All rights reserved.
//#import <Foundation/Foundation.h>@interface Person : NSObject <NSCopying>@property(nonatomic,retain)NSMutableArray *apples;
@property(nonatomic)int age;@end

Person.m

//
//  Person.m
//  31_DeepCopy
//
//  Created by jiangwei on 14-10-13.
//  Copyright (c) 2014年 jiangwei. All rights reserved.
//#import "Person.h"@implementation Person- (id)copyWithZone:(NSZone *)zone{//创建一个新的副本对象//这个方法是会被继承的,所以这里还是不用//[Person allocWithZone:<#(struct _NSZone *)#>];Person * p = [[self class] allocWithZone:zone];//p.apples = _apples;//是指针赋值,所以还是浅拷贝//深拷贝//拷贝之后引用计数会+1,需要release以下p.apples = [_apples mutableCopy];p.age = _age;[p.apples release];//但是如果我们使用->语法就不需要了,因为我们没有使用set方法,引用计数没有操作//但是这种方式我们不采用//p->_apples = [_apples mutableCopy];return p;
}@end

我们看到,Person实现了NSCopying协议,然后需要实现一个方法:copyWithZone

在这个方法中我们开始进行拷贝操作:

Person类中有一个属性类型是数组

这里我们需要生成一个Person对象,然后进行属性的拷贝,最后在返回这个对象

浅拷贝:直接复制数组指针

深拷贝:直接复制数组的内容,这里可以直接使用mutableCopy方法进行实现

测试类

main.m

//
//  main.m
//  31_DeepCopy
//
//  Created by jiangwei on 14-10-13.
//  Copyright (c) 2014年 jiangwei. All rights reserved.
//#import <Foundation/Foundation.h>
#import "Person.h"//深拷贝和浅拷贝
//默认是浅拷贝
int main(int argc, const char * argv[]) {@autoreleasepool {NSMutableArray *array1 = [NSMutableArray arrayWithCapacity:2];for(int i=0;i<2;i++){Person *p = [[Person alloc] init];[array1 addObject:p];[p release];}//引用计数都是1for(Person *p in array1){NSLog(@"复制之前的引用计数:%ld",p.retainCount);NSLog(@"复制之前的指针:%p",p);}//引用计数都是2,因为是浅拷贝,又有指针指向对象了,array2也是使用了person//浅拷贝:只拷贝对象指针//深拷贝:复制属性NSArray *array2 = [array1 copy];for(Person *p in array2){NSLog(@"复制之前的引用计数:%ld",p.retainCount);NSLog(@"复制之前的指针:%p",p);}//这里Person中有一个属性是NSMutableArray,但是我们只是赋值,并不是拷贝//所以这里还不算是深拷贝Person *p = [[Person alloc] init];p.apples = [NSMutableArray arrayWithObjects:@"iphone",@"ipad", nil];p.age = 20;Person *p1 = [p copy];if(p != p1){NSLog(@"p1.age=%d",p1.age);NSLog(@"p1.apples=%@",p1.apples);}}return 0;
}

三、字符串的拷贝

//
//  main.m
//  32_NSStringCopy
//
//  Created by jiangwei on 14-10-13.
//  Copyright (c) 2014年 jiangwei. All rights reserved.
//#import <Foundation/Foundation.h>#import "Person.h"//字符串为什么使用copy
int main(int argc, const char * argv[]) {@autoreleasepool {Person *p = [[Person alloc] init];NSMutableString *name = [NSMutableString stringWithString:@"jack"];p.name = name;//人的名字被修改了//如果Person的name是retain,则此处的name和person对象的name执行的是同一个字符串对象//此处的name修改之后,会导致person的name也被修改,破坏了person对象的封装性//正常情况下,我们会使用set方法设置名字//所以如果使用的是copy的话,就不会修改名字了[name appendString:@"-tom"];//Foundation框架中可复制的对象,当我们拷贝的是一个不可变对象时候//他的作用相当于retain(系统做的内存优化)//所以这里的如果换成NSString类型的时候,其实没有拷贝的动作的,因为NSString是不可变的//但是使用mutableCopy就可以做到拷贝了,mutableCopy是真正意义上的拷贝//mutableCopy拷贝方法,不管什么对象都是真实拷贝//[不可变对象 copy]是假拷贝,等价于[不可变对象 retain]//[不可变对象 mutableCopy是真拷贝}return 0;
}

这里为什么要单独说一下字符串的拷贝呢?

因为字符串是一个特殊的对象,我们应该调用他的copy方法。因为我们对于字符串其实我们是期望他只有一分值得,就看上面的例子:

我们用NSMutableString产生一个name,然后将其赋值给person对象,当我们在外面修改name的内容的时候,其实person的name属性的值也应该修改。所以我们一般在拷贝字符串对象的时候,都会调用他的copy方法

总结

这一篇文章主要介绍了OC中对象拷贝的相关概念和知识点。我们在操作对象的时候,有时候进行拷贝,还要仔细考虑一下是深拷贝还是浅拷贝。

转载于:https://www.cnblogs.com/roccheung/p/5797287.html

OC学习篇之---对象的拷贝相关推荐

  1. OC学习篇之---归档和解挡

    今天我们来看一下OC中的一个重要知识点:归档 OC中的归档就是将对象写入到一个文件中,Java中的ObjectInputStream和ObjectOutputStream来进行操作的.当然在操作的这些 ...

  2. (转载)OC学习篇之---KVC和KVO操作

    前一篇文章我们介绍了OC中最常用的文件操作,那么今天来看一下OC中的一个比较有特色的知识点:KVC和KVO 一.KVC操作 OC中的KVC操作就和Java中使用反射机制去访问类的private权限的变 ...

  3. OC学习篇之---代理模式

    在前一篇文章我们介绍了OC中的协议的概念:http://blog.csdn.net/jiangwei0910410003/article/details/41776015,这篇文章我们就来介绍一下OC ...

  4. OC学习篇之---类的初始化方法和点语法的使用

    一.首先来看一下类的初始化方法 在Java中我们知道一个每个类都有构造方法,这里的初始化方法就是和构造方法一个概念的,但是这里有一个区别是:Java中有默认构造方法,当我们去自定义构造方法的时候,这个 ...

  5. (转载)OC学习篇之---Foundation框架中的NSDirctionary类以及NSMutableDirctionary类

    昨天学习了Foundation框架中NSArray类和NSMutableArray类,今天来看一下Foundation框架中的NSDirctionary类,NSMutableDirctionary类, ...

  6. python学习高级篇(part9)--对象的引用计数

    学习笔记,仅供参考,有错必纠 文章目录 python 学习高级篇 类对象的特殊方法之`__str__()` 类对象的特殊方法之`__new__()` 对象的引用计数 什么是引用计数 对象的引用计数加1 ...

  7. “睡服”面试官系列第十五篇之对象的扩展(建议收藏学习)

    目录 1. 属性的简洁表示法 2. 属性名表达式 3. 方法的 name 属性 4. Object.is() 5. Object.assign() 5.1基本用法 5.2注意点 5.21.浅拷贝 5. ...

  8. jQuery学习笔记系列(三)——事件注册、事件处理、事件对象、拷贝对象、多库共存、jQuery插件、toDoList综合案例

    day03 - jQuery 学习目标: 能够说出4种常见的注册事件 能够说出 on 绑定事件的优势 能够说出 jQuery 事件委派的优点以及方式 能够说出绑定事件与解绑事件 能够说出 jQuery ...

  9. c++学习笔记(12) 需要对对象做拷贝时(深拷贝,浅拷贝),如何重载赋值运算符

    在c++学习笔记(8)中,介绍了拷贝构造函数的概念:涉及到深拷贝和浅拷贝的概念: 拷贝构造函数:每一个类都有一个都有一个拷贝构造函数,用于拷贝对象.拷贝构造函数可以用来创建一个对象,并用另一个对象的数 ...

最新文章

  1. 如何优雅安全地在深层数据结构中取值
  2. vuejs和html语言一样么,vue和vue.js有区别吗?
  3. Java使用OpenCV实现人脸识别
  4. php信息采集开发,程序php信息采集程序代码
  5. GIT项目管理工具(part1)--简介及概念
  6. mysql 子查询模糊匹配_sql中的查询(模糊查询,子查询,联表查询)
  7. poj 1733 ParityGame 并查集 离散化
  8. c语言ics什么意思,[转载]C网来话筛选(ICS)业务及实现
  9. oracle查找clob中的值,Oracle 查找带有CLOB字段的所有表
  10. 《图像理解理论与方法》(1)
  11. Delphi BLE 控件
  12. linux驱动基础开发2——linux 驱动开发前奏(模块编程)-转
  13. 如何把IDEA项目与上传到Git中
  14. VB模拟键盘输入的N种方法
  15. cygwin中访问windows分区
  16. CRC码计算及校验原理计算
  17. 《FLUENT 14流场分析自学手册》——1.4 流体运动及换热的多维方程组
  18. matlab h系统控制器,Matlab的H_inf鲁棒控制器的设计.pdf
  19. Android:异步处理之Handler+Thread的应用(一)
  20. MongoDB可视化客户端管理工具之NoSQLbooster4mongo

热门文章

  1. 2022-2028年中国聚碳酸亚丙酯(PPC)行业市场深度分析及未来趋势预测报告
  2. Docker 入门系列(7)- Dockerfile 使用(FROM、RUN、CMD、EXPOSE、ENV、ADD、COPY、ENTRYPOINT、VOLUME、WORKDIR)
  3. 【VB】学生信息管理系统4——数据库的发展
  4. [Pytorch]基于混和精度的模型加速
  5. react非常适合入门者学习使用的后台管理框架
  6. TVM 各个模块总体架构
  7. NVIDIA A100 GPUs上硬件JPEG解码器和NVIDIA nvJPEG库
  8. 深度学习与传统图像识别
  9. centos7 安装Git
  10. 高频开关电源原理_程控开关电源的工作原理