OC中的对象拷贝概念,这个对于面向对象语言中都会有这种的问题,只是不同的语言有不同的解决方式:C++中有拷贝构造函数,Java中需要实现Cloneable接口,在clone方法中进行操作。但是不过OC更偏向于Java这种方式,OC中如果一个对象需要被拷贝,他需要实现协议:
<NSCopying><NSMutableCopying>
从名字上我们可以看到,一个协议是用于不可变对象的,一个协议适用于可变对象的

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

一、系统类对象的拷贝
[objc]  view plaincopy
1. //  
2. //  main.m  
3. //  30_CopyObject  
4. //  
5. //  Created by jiangwei on 14-10-13.  
6. //  Copyright (c) 2014年 jiangwei. All rights reserved.  
7. //  
8.   
9. #import <Foundation/Foundation.h>  
10.   
11. /** 
12.   
13.  */  
14. int main(int argc, const charchar * argv[]) {  
15.     @autoreleasepool {  
16.           
17.         //对象具备拷贝功能,必须实现如下协议  
18.         //<NSCopying>、<NSMutableCopying>  
19.           
20.         //copy方法返回的是一个不可变对象,mutableCopy方法返回的是一个可变对象  
21.           
22.         /* 
23.         NSMutableArray *array1 = [NSMutableArray arrayWithObjects:@"one",@"two",nil]; 
24.         NSMutableArray *array2 = [array1 retain]; 
25.         //retain只是引用计数+1,没有创建新的对象 
26.         //array1与array2指针相同,指向同一个对象 
27.         if(array1 == array2){ 
28.             NSLog(@"array1 == array2"); 
29.             NSLog(@"array1的引用计数:%ld",array1.retainCount); 
30.         } 
31.          */  
32.           
33.         NSMutableArray *array1 = [NSMutableArray arrayWithObjects:@"one",@"two",nil];  
34.         //复制对象,创建一个新的副本对象  
35.         //这里使用copy方法复制,返回的是一个不可变数组,但是用一个可变数组来声明,但是我们关心的是指针的的内容,而不是类型  
36.         //所以array2的真实类型还是不可变类型的  
37.         NSMutableArray *array2 = [array1 copy];//array2计数为:1,因为是新创建出来的对象  
38.           
39.         //使用mutableCopy方法,返回的就是可变数组  
40.         //当然这种方法只针对于那些有可变对象之分有用,对于其他的对象这个方法和copy方法的效果是一样的  
41.         NSMutableArray *array3 = [array1 mutableCopy];  
42.           
43.         if(array1 != array2){  
44.             NSLog(@"array1 != array2");  
45.             NSLog(@"array1的引用计数:%ld",array1.retainCount);  
46.             NSLog(@"array2的引用计数:%ld",array2.retainCount);  
47.         }  
48.         [array2 release];  
49.         [array1 release];  
50.           
51.           
52.     }  
53.     return 0;  
54. }  
我们看到,NSMutableArray有一个mutableCopy方法,这样返回的一个数组对象就是一个拷贝对象了。
但是这里需要注意的是:
copy方法和mutableCopy方法的区别
这两个方法的区别只在于那些有可变对象和不可变对象之分的对象上,对于没有这种区分的对象来说,这两个方法的效果是一样的。
[不可变对象 copy]是假拷贝,等价于[不可变对象 retain]
[不可变对象 mutableCopy是真拷贝

二、深拷贝和浅拷贝
在拷贝对象中也是有深拷贝和浅拷贝之分的
浅拷贝:只拷贝所有属性对象的指针
深拷贝:拷贝属性对象的内容
看个例子:
Person.h
[objc]  view plaincopy
1. //  
2. //  Person.h  
3. //  31_DeepCopy  
4. //  
5. //  Created by jiangwei on 14-10-13.  
6. //  Copyright (c) 2014年 jiangwei. All rights reserved.  
7. //  
8.   
9. #import <Foundation/Foundation.h>  
10.   
11. @interface Person : NSObject <NSCopying>  
12.   
13. @property(nonatomic,retain)NSMutableArray *apples;  
14. @property(nonatomic)int age;  
15.   
16. @end

Person.m
[objc]  view plaincopy
1. //  
2. //  Person.m  
3. //  31_DeepCopy  
4. //  
5. //  Created by jiangwei on 14-10-13.  
6. //  Copyright (c) 2014年 jiangwei. All rights reserved.  
7. //  
8.   
9. #import "Person.h"  
10.   
11. @implementation Person  
12.   
13. - (id)copyWithZone:(NSZone *)zone{  
14.     //创建一个新的副本对象  
15.     //这个方法是会被继承的,所以这里还是不用  
16.     //[Person allocWithZone:<#(struct _NSZone *)#>];  
17.     Person * p = [[self class] allocWithZone:zone];  
18.     //p.apples = _apples;//是指针赋值,所以还是浅拷贝  
19.     //深拷贝  
20.     //拷贝之后引用计数会+1,需要release以下  
21.     p.apples = [_apples mutableCopy];  
22.     p.age = _age;  
23.       
24.     [p.apples release];  
25.       
26.     //但是如果我们使用->语法就不需要了,因为我们没有使用set方法,引用计数没有操作  
27.     //但是这种方式我们不采用  
28.     //p->_apples = [_apples mutableCopy];  
29.       
30.     return p;  
31. }  
32.   
33. @end  
我们看到,Person实现了NSCopying协议,然后需要实现一个方法:copyWithZone
在这个方法中我们开始进行拷贝操作:
Person类中有一个属性类型是数组
这里我们需要生成一个Person对象,然后进行属性的拷贝,最后在返回这个对象
浅拷贝:直接复制数组指针
深拷贝:直接复制数组的内容,这里可以直接使用mutableCopy方法进行实现

测试类
main.m
[objc]  view plaincopy
1. //  
2. //  main.m  
3. //  31_DeepCopy  
4. //  
5. //  Created by jiangwei on 14-10-13.  
6. //  Copyright (c) 2014年 jiangwei. All rights reserved.  
7. //  
8.   
9. #import <Foundation/Foundation.h>  
10. #import "Person.h"  
11.   
12. //深拷贝和浅拷贝  
13. //默认是浅拷贝  
14. int main(int argc, const charchar * argv[]) {  
15.     @autoreleasepool {  
16.           
17.         NSMutableArray *array1 = [NSMutableArray arrayWithCapacity:2];  
18.           
19.         for(int i=0;i<2;i++){  
20.             Person *p = [[Person alloc] init];  
21.             [array1 addObject:p];  
22.             [p release];  
23.         }  
24.           
25.         //引用计数都是1  
26.         for(Person *p in array1){  
27.             NSLog(@"复制之前的引用计数:%ld",p.retainCount);  
28.             NSLog(@"复制之前的指针:%p",p);  
29.         }  
30.           
31.         //引用计数都是2,因为是浅拷贝,又有指针指向对象了,array2也是使用了person  
32.         //浅拷贝:只拷贝对象指针  
33.         //深拷贝:复制属性  
34.         NSArray *array2 = [array1 copy];  
35.         for(Person *p in array2){  
36.             NSLog(@"复制之前的引用计数:%ld",p.retainCount);  
37.             NSLog(@"复制之前的指针:%p",p);  
38.         }  
39.           
40.         //这里Person中有一个属性是NSMutableArray,但是我们只是赋值,并不是拷贝  
41.         //所以这里还不算是深拷贝  
42.         Person *p = [[Person alloc] init];  
43.         p.apples = [NSMutableArray arrayWithObjects:@"iphone",@"ipad", nil nil];  
44.         p.age = 20;  
45.           
46.         Person *p1 = [p copy];  
47.           
48.         if(p != p1){  
49.             NSLog(@"p1.age=%d",p1.age);  
50.             NSLog(@"p1.apples=%@",p1.apples);  
51.         }  
52.           
53.     }  
54.     return 0;  
55. }

三、字符串的拷贝
[objc]  view plaincopy
1. //  
2. //  main.m  
3. //  32_NSStringCopy  
4. //  
5. //  Created by jiangwei on 14-10-13.  
6. //  Copyright (c) 2014年 jiangwei. All rights reserved.  
7. //  
8.   
9. #import <Foundation/Foundation.h>  
10.   
11. #import "Person.h"  
12.   
13. //字符串为什么使用copy  
14. int main(int argc, const charchar * argv[]) {  
15.     @autoreleasepool {  
16.         Person *p = [[Person alloc] init];  
17.         NSMutableString *name = [NSMutableString stringWithString:@"jack"];  
18.         p.name = name;  
19.           
20.         //人的名字被修改了  
21.         //如果Person的name是retain,则此处的name和person对象的name执行的是同一个字符串对象  
22.         //此处的name修改之后,会导致person的name也被修改,破坏了person对象的封装性  
23.         //正常情况下,我们会使用set方法设置名字  
24.         //所以如果使用的是copy的话,就不会修改名字了  
25.         [name appendString:@"-tom"];  
26.           
27.         //Foundation框架中可复制的对象,当我们拷贝的是一个不可变对象时候  
28.         //他的作用相当于retain(系统做的内存优化)  
29.           
30.         //所以这里的如果换成NSString类型的时候,其实没有拷贝的动作的,因为NSString是不可变的  
31.         //但是使用mutableCopy就可以做到拷贝了,mutableCopy是真正意义上的拷贝  
32.         //mutableCopy拷贝方法,不管什么对象都是真实拷贝  
33.           
34.         //[不可变对象 copy]是假拷贝,等价于[不可变对象 retain]  
35.         //[不可变对象 mutableCopy是真拷贝  
36.     }  
37.     return 0;  
38. }  
这里为什么要单独说一下字符串的拷贝呢?
因为字符串是一个特殊的对象,我们应该调用他的copy方法。因为我们对于字符串其实我们是期望他只有一分值得,就看上面的例子:
我们用NSMutableString产生一个name,然后将其赋值给person对象,当我们在外面修改name的内容的时候,其实person的name属性的值也应该修改。所以我们一般在拷贝字符串对象的时候,都会调用他的copy方法

总结

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

OC中对象拷贝概念的更多相关文章

  1. OC中协议的概念以及用法

    OC中协议的概念以及用法,协议也是OC中的一个重点,Foundation框架以及我们后面在写代码都会用到. OC中的协议就是相当于Java中的接口(抽象类),只不过OC中的名字更形象点,因为我们在学习 ...

  2. [BS-21] 关于OC中对象与指针的思考

    关于OC中对象与指针的思考 1. 创建对象: OC中可通过代码Person *p = [[Person alloc] init];创建了一个对象p.该过程中内存情况为: 在当前线程的栈(默认1M)中, ...

  3. OC中对象元素的引用计数 自动释放池的相关概念

    OC中数组对象在是如何处理对象元素的引用计数问题的,同时介绍一下自动释放池的相关概念 一.数组对象是如何处理对象元素的引用计数问题[objc]  view plaincopy 1. //   2. / ...

  4. 编译时和运行时、OC中对象的动态编译机制

    编译时 编译时顾名思义就是正在编译的时候.那啥叫编译呢?就是编译器帮你把源代码翻译成机器能识别的代码.(当然只是一般意义上这么说,实际上可能只是翻译成某个中间状态的语言.比如Java只有JVM识别的字 ...

  5. Java中对象拷贝的两种方式

    引用的拷贝 //引用拷贝 private static void copyReferenceObject(){ Person p = new Person(23, "zhang") ...

  6. 谈谈Python中对象拷贝

    你想复制一个对象?因为在Python中,无论你把对象做为参数传递,做为函数返回值,都是引用传递的. 何谓引用传递,我们来看一个C++交换两个数的函数: void swap(int &a, in ...

  7. oc中对象的初始化

    在.m文件中使用对象方法: - (id)init { _name =@"zhangsan"; _age = 18; return self; } 然后通过main方法中进行创建对象 ...

  8. OC中对象的description方法

    周所周知,我们在做项目时, 可以在类的.m文件中重写该类的对象的描述description方法: 示例: -(NSString *)description{    NSString *str = [N ...

  9. OC中的一个特性:延展

    OC中的一个特性:延展其实说白了,延展就是弥补C语言中的前向申明,我们知道,在C语言中,如果你想调用一个函数的话,那么在此之前必须要声明一个这个函数,就是有前置性.OC中为了弥补C语言中的这个问题,就 ...

随机推荐

  1. C#调用HTTP接口

    string url = "http://www.***.com?id=123&username=test&userpwd=*****"; WebRequest w ...

  2. [置顶] Firefox OS 学习——简单了解知识

    什么是Firefox OS ? Firefox OS 是一个为网页设计而生的能编译和独立的手机网页操作系统,我们相信在接下来的时代,网页应用将充满整个新兴操作设备,这也为当前许多网页开发者不需要太多的 ...

  3. SQL Server中的sysobjects

    摘自:http://www.cnblogs.com/bugY/archive/2011/09/21/2184182.html 关于SQL Server数据库的一切信息都保存在它的系统表格里.我怀疑你是 ...

  4. fseek/ftell/rewind/fgetpos/fsetpos函数使用-linux

    程序: #include<stdio.h> int main(int argc,char *argv[]) { FILE * stream; fpos_t pos; stream = fo ...

  5. 推荐JVM的9款编程语言杀手开发利器

    随着各种各样的编程语言铺地盖地向我们涌来,软件世界似乎变得有点疯狂了.JVM的帝国在不断地壮大,它已经不满足于只作为Java语言的运行平台.它勇敢地将自己的触角伸向了JRuby,Groovy等等,未来 ...

  6. js事件的相关收集

    1.阻止事件冒泡: IE:cancelBubble = true; 其他: stopPropagation(); 2.阻止事件的默认行为: IE: returnValue = false; 其他: p ...

  7. Asp.Net MVC4下设置W3P3(IIS)调试步骤

    环境] VS 2012  IIS7.5 [问题] MVC项目在创建时和APS.NET不同,不能够选择服务器类型,不能够直接把项目创建到IIS上. 如果在项目中直接更改属性,更换调试服务器类型,会报错 ...

  8. Jquery揭秘系列:谈谈bind,one,live,delegate,on事件及实现

    在Jquery里面,我们用的最多的就是事件绑定了,事件绑定有多个函数.例如:bind,one,live,delegate,on等等. on() jQuery事件绑定.on()简要概述及应用 看源码发现 ...

  9. C#获取本周、上周、本月、上月、本季度、上季度、本年、上一年起始时间和结束时间

    /// 取得某月的第一天 /// </summary> /// <param name="datetime">要取得月份第一天的时间</param&g ...

  10. android stuido 快捷键

    Alt+回车 导入包,自动修正 Ctrl+N   查找类 Ctrl+Shift+N 查找文件 Ctrl+Alt+L  格式化代码 Ctrl+Alt+O 优化导入的类和包 Alt+Insert 生成代码 ...