OC中对象拷贝概念

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中对象拷贝的相关概念和知识点。我们在操作对象的时候,有时候进行拷贝,还要仔细考虑一下是深拷贝还是浅拷贝。

时间: 2024-10-13 17:11:15

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

OC中协议的概念以及用法

OC中协议的概念以及用法,协议也是OC中的一个重点,Foundation框架以及我们后面在写代码都会用到. OC中的协议就是相当于Java中的接口(抽象类),只不过OC中的名字更形象点,因为我们在学习Java中的接口时候,看可以知道其实接口就相当于一种契约(协议),给他的实现类打上标记了,当然这个活在Java5.0之后,被注解替代了,因为注解就是为了此功能诞生的.协议就是定义了一组方法,然后让其他类去实现 下面来看代码:WithProtocol.h[objc]  view plaincopy 

oc中对象的初始化

在.m文件中使用对象方法: - (id)init { _name [email protected]“zhangsan”; _age = 18; return self; } 然后通过main方法中进行创建对象并初始化:例如: Person *p1 = [[Person alloc] init]; 类方法alloc是分配内存空间,对象方法init是初始化. oc中对象的初始化

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

OC中数组对象在是如何处理对象元素的引用计数问题的,同时介绍一下自动释放池的相关概念 一.数组对象是如何处理对象元素的引用计数问题[objc]  view plaincopy 1. //   2. //  main.m   3. //  26_NSArrayMemeryManager   4. //   5. //  Created by jiangwei on 14-10-12.   6. //  Copyright (c) 2014年 jiangwei. All rights reserve

个人总结诀窍----oc中对象作为方法连续,重点也是难点.

相信有不少初学者,oc中的对象作为方法连续传递在一两个对象的时候可能还好,多了可能就绕晕了...我接下来就分享一下我个人对这一块的知识的总结或心得或诀窍吧. 我觉得用"螳螂捕蝉黄雀在后"比较形象,关键点就一环套一环,怎么去打比方还是看个人理解了... 举个例子:一个顾客要去一家餐馆吃饭,餐馆有厨师,厨师有食材.以上有对象分别为:顾客,餐馆,厨师,食材; 一.先来理解这2段关于顾客的代码. #import <Foundation/Foundation.h> #import &

OC中nil、Nil、NULL、NSNull的区别

nil:指向OC中对象的空指针 e.g.: NSString *string = nil; Nil:指向OC中类的空指针    e.g.:Class class = Nil; NULL:指向其他类型的空指针 e.g.:int a = NULL; NSNull:OC中的对象,表示空值; 注:nil是一个对象,NULL是一个值 nil是将对象设置为空,NULL是将基本类型设置为空 e.g. (1) class *object = nil;  [object message];  result:NO

OC中的一个特性:延展

OC中的一个特性:延展其实说白了,延展就是弥补C语言中的前向申明,我们知道,在C语言中,如果你想调用一个函数的话,那么在此之前必须要声明一个这个函数,就是有前置性.OC中为了弥补C语言中的这个问题,就有了延展的概念,下面来看一下代码:Person.h[objc]  view plaincopy 1. //   2. //  Person.h   3. //  10_CategoryExtend   4. //   5. //  Created by jiangwei on 14-10-11.  

Java 开发中的对象拷贝

前言 在 Java 开发中,很多时候需要将两个属性基本相同的对象进行属性复制,比如 DO 转 VO等等. 本文主要介绍自己实现的简易拷贝工具类与 Spring 提供的属性拷贝的对比. Spring 提供的属性拷贝 在 Spring 中直接调用 BeanUtils.copyProperties();即可. 它的核心通过循环 target 的所有方法名,然后在 source 中找到对应的方法名,最后通过反射从 source 中获取并写入 target 中. Spring 没有通过 java.lang

python中的对象拷贝

python中无论参数传递还是函数返回值,都是进行引用传递.那如何拷贝对象呢,标准库的copy模块提供了两个方法:copy和deepcopy方法. 1. copy.copy 浅拷贝 只拷贝父对象,不会拷贝对象的内部的子对象. 2. copy.deepcopy 深拷贝 拷贝对象及其子对象 见下例: import copy a = [1, 2, 3, 4, ['a', 'b']] #原始对象 e = a[:] #利用分片操作进行拷贝(浅拷贝) b = a <span style="white-

OC中保存自定义类型对象的持久化方法

OC中如果要将自定义类型的对象保存到文件中,必须进行以下三个条件: 想要把存放自定义类型的数组进行 持久化(就是将内存中的临时数据以文件<数据库等>的形式写到磁盘上)必须满足: 1. 自定义对象必须要序列化(将数据有序的存放) 2. 需要使用归档来进行持久化 3. 如果要加载持久化文件需要进行反序列化(就是将有序存放的数据读取并变成自定义对象) 第一要将自定义类型序列化以及第三步并将文件反序列化必须实现OC中的  <NSCoding>协议. 以Student类为例 @interfa