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中协议的概念以及用法
OC中协议的概念以及用法,协议也是OC中的一个重点,Foundation框架以及我们后面在写代码都会用到. OC中的协议就是相当于Java中的接口(抽象类),只不过OC中的名字更形象点,因为我们在学习 ...
- [BS-21] 关于OC中对象与指针的思考
关于OC中对象与指针的思考 1. 创建对象: OC中可通过代码Person *p = [[Person alloc] init];创建了一个对象p.该过程中内存情况为: 在当前线程的栈(默认1M)中, ...
- OC中对象元素的引用计数 自动释放池的相关概念
OC中数组对象在是如何处理对象元素的引用计数问题的,同时介绍一下自动释放池的相关概念 一.数组对象是如何处理对象元素的引用计数问题[objc] view plaincopy 1. // 2. / ...
- 编译时和运行时、OC中对象的动态编译机制
编译时 编译时顾名思义就是正在编译的时候.那啥叫编译呢?就是编译器帮你把源代码翻译成机器能识别的代码.(当然只是一般意义上这么说,实际上可能只是翻译成某个中间状态的语言.比如Java只有JVM识别的字 ...
- Java中对象拷贝的两种方式
引用的拷贝 //引用拷贝 private static void copyReferenceObject(){ Person p = new Person(23, "zhang") ...
- 谈谈Python中对象拷贝
你想复制一个对象?因为在Python中,无论你把对象做为参数传递,做为函数返回值,都是引用传递的. 何谓引用传递,我们来看一个C++交换两个数的函数: void swap(int &a, in ...
- oc中对象的初始化
在.m文件中使用对象方法: - (id)init { _name =@"zhangsan"; _age = 18; return self; } 然后通过main方法中进行创建对象 ...
- OC中对象的description方法
周所周知,我们在做项目时, 可以在类的.m文件中重写该类的对象的描述description方法: 示例: -(NSString *)description{ NSString *str = [N ...
- OC中的一个特性:延展
OC中的一个特性:延展其实说白了,延展就是弥补C语言中的前向申明,我们知道,在C语言中,如果你想调用一个函数的话,那么在此之前必须要声明一个这个函数,就是有前置性.OC中为了弥补C语言中的这个问题,就 ...
随机推荐
- #include <boost/asio.hpp>
TCP服务端和客户端 TCP服务端 #include <iostream> #include <stdlib.h> #include <boost/asio.hpp> ...
- hdu 5606 tree(并查集)
Problem Description There is a tree(the tree is a connected graph which contains n points and n−1 ed ...
- flex 载入GIF图片
李石磊 学习日记 一.下载GIFPlayer包 二.源代码例如以下: <?xml version="1.0" encoding="utf-8"?> ...
- 使用OAuth2.0访问豆瓣API
如何计算某个用户的access_token过期时间?开发者可以通过两种方式计算:用户授权时,oauth2/access_token接口返回的expires_in值就是access_token的生命周期 ...
- Windows XPE 安装
to liuxiyao: 出现这样的问题我推断是由于系统有一些必须的dll类库没有被build进系统中,你在构建时多加入一些系统组件试试.(我想通过评论发可是发了5.6遍CSDN没反应,就写到这里吧, ...
- Permutations,Permutations II,Combinations
这是使用DFS来解数组类题的典型题目,像求子集,和为sum的k个数也是一个类型 解题步骤: 1:有哪些起点,例如,数组中的每个元素都有可能作为起点,那么用个for循环就可以了. 2:是否允许重复组合 ...
- mysql5.6 zip版安装
MySQL安装文件分为两种,一种是msi格式的,一种是zip格式的.如果是msi格式的可以直接点击安装,按照它给出的安装提示进行安装(相信大家的英文可以看懂英文提示),一般MySQL将会安装在C:\P ...
- AutoCompleteTextView 和 TextWatcher 详解
TextWatcher 监测Edittext内容的变化------------------------------------------------------------------------- ...
- javascript 数据结构和算法读书笔记 > 第三章 列表
1. 结构分析 列表首先要有以下几个属性: listSize 长度 pos 当前位置 dataStore 数据 我们要通过以下方法对上面三个属性进行操作: length() 获取长度 | getPos ...
- php 表单校验函数库(判断email格式是否正确、http地址是否合法有效、手机号码是否合法)
/** * 表单校验函数库 */ /** * 判断email格式是否正确 * @param $email */ function is_email($email) { return strlen($e ...