浅析ObjectiveC 深浅拷贝学习

来源:互联网 发布:北京碧水源 知乎 编辑:程序博客网 时间:2024/06/04 18:11

在ObjectiveC 中,什么是深浅拷贝? 深浅拷贝分别指深拷贝和浅拷贝,即mutableCopy和copy方法。

copy复制一个不可变对象,而mutableCopy复制一个mutable可变对象。

什么时候用到深浅拷贝?下面举几个例子说明。 非容器类对象 如NSString,NSNumber等一类对象 

示例1:

  1. // 非容器类对象
  2. NSString *str = @"origin string";
  3. NSString *strCopy = [str copy];
  4. NSMutableString *mstrCopy = [str mutableCopy];
  5. [mstrCopy appendString:@"??"];

查看内存可以发现,str和strCopy指向的是同一块内存区域,我们称之为弱引用(weak reference)。而mstrCopy是真正的复制,系统为其分配了新内存空间,保存从str复制过来的字符串值。从最后一行代码中修改这些值而不影响str和strCopy中可证明。

示例2:

  1. NSMutableString *mstr = [NSMutableString stringWithString:@"origin"];
  2. NSString *strCopy = [mstr copy];
  3. NSMutableString *mstrCopy = [mstr copy];
  4. NSMutableString *mstrMCopy = [mstr mutableCopy];
  5. //[mstrCopy appendString:@"1111"]; //error
  6. [mstr appendString:@"222"];
  7. [mstrMCopy appendString:@"333"];

以上四个对象所分配的内存都是不一样的。而且对于mstrCopy,它所指向的其实是一个imutable对象,是不可改变的,所以会出错。这点要注意,好好理解。

容器类对象深浅复制

比如NSArray,NSDictionary等。对于容器类本身,上面讨论的结论也适用的,下面探讨的是复制后容器内对象的变化。

示例3

  1. /* copy返回不可变对象,mutablecopy返回可变对象 */
  2. NSArray *array1 = [NSArray arrayWithObjects:@"a",@"b",@"c",nil];
  3. NSArray *arrayCopy1 = [array1 copy];
  4. //arrayCopy1是和array同一个NSArray对象(指向相同的对象),包括array里面的元素也是指向相同的指针
  5. NSLog(@"array1 retain count: %d",[array1 retainCount]);
  6. NSLog(@"array1 retain count: %d",[arrayCopy1 retainCount]);
  7. NSMutableArray *mArrayCopy1 = [array1 mutableCopy];
  8. //mArrayCopy1是array1的可变副本,指向的对象和array1不同,但是其中的元素和array1中的元素指向的还是同一个对象。mArrayCopy1还可以修改自己的对象
  9. [mArrayCopy1 addObject:@"de"];
  10. [mArrayCopy1 removeObjectAtIndex:0];

array1和arrayCopy1是指针复制,而mArrayCopy1是对象复制,符合前面示例1讨论的结论。mArrayCopy1可以改变其内的元素:删除或添加。但容器内的元素内容都是浅拷贝。

示例4

  1. NSArray *mArray1 = [NSArray arrayWithObjects:[NSMutableString stringWithString:@"a"],@"b",@"c",nil];
  2. NSLog(@"mArray1 retain count: %d",[mArray1 retainCount]);
  3. NSArray *mArrayCopy2 = [mArray1 copy];
  4. NSLog(@"mArray1 retain count: %d",[mArray1 retainCount]);
  5. // mArray1和mArrayCopy2指向同一对象,retain值+1。
  6. NSMutableArray *mArrayMCopy1 = [mArray1 mutableCopy];
  7. NSLog(@"mArray1 retain count: %d",[mArray1 retainCount]); //mArrayCopy2和mArray1指向的是不一样的对象,但是其中的元素都是一样的对象——同一个指针
  8. NSMutableString *testString = [mArray1 objectAtIndex:0];
  9. //testString = @"1a1";//这样会改变testString的指针,其实是将@“1a1”临时对象赋给了testString
  10. [testString appendString:@" tail"];//这样以上三个数组的首元素都被改变了

由此可见,对于容器而言,其元素对象始终是指针复制。如果需要元素对象也是对象复制,就需要实现深拷贝。http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Collections/Articles/Copying.html

示例5

  1. NSArray *array = [NSArray arrayWithObjects:[NSMutableString stringWithString:@"first"],[NSStringstringWithString:@"b"],@"c",nil];
  2. NSArray *deepCopyArray=[[NSArray alloc] initWithArray: array copyItems: YES];
  3. NSArray* trueDeepCopyArray = [NSKeyedUnarchiver unarchiveObjectWithData:
  4. [NSKeyedArchiver archivedDataWithRootObject: array]];

trueDeepCopyArray是完全意义上的深拷贝,而deepCopyArray则不是,对于deepCopyArray内的不可变元素其还是指针复制。

或者我们自己实现深拷贝的方法。因为如果容器的某一元素是不可变的,那你复制完后该对象仍旧是不能改变的,因此只需要指针复制即可。除非你对容器内的元素重新赋值,否则指针复制即已足够。

举个例子,[[array objectAtIndex:0]appendstring:@”sd”]后其他的容器内对象并不会受影响。[[array objectAtIndex:1]和[[deepCopyArray

objectAtIndex:0]尽管是指向同一块内存,但是我们没有办法对其进行修改——因为它是不可改变的。所以指针复制已经足够。所以这并不是完全意义上的深拷贝。

自己实现深拷贝的方法

NSDictionaryMutableDeepCopy.h

  1. 8 #import <foundation /Foundation.h>
  2. @interface NSDictionary(MutableDeepCopy)
  3. - (NSMutableDictionary *)mutableDeepCopy;
  4. @end
  5. </foundation>
  6. NSDictionaryMutableDeepCopy.m
  7. #import "NSDictionaryMutableDeepCopy.h"
  8. @implementation NSDictionary(MutableDeepCopy)
  9. - (NSMutableDictionary *)mutableDeepCopy {
  10. NSMutableDictionary *ret = [[NSMutableDictionary alloc]
  11. initWithCapacity:[self count]];
  12. NSArray *keys = [self allKeys];
  13. for (id key in keys) {
  14. id oneValue = [self valueForKey:key];
  15. id oneCopy = nil;
  16. if ([oneValue respondsToSelector:@selector(mutableDeepCopy)]) {
  17. oneCopy = [oneValue mutableDeepCopy];
  18. }
  19. else if ([oneValue respondsToSelector:@selector(mutableCopy)]) {
  20. oneCopy = [oneValue mutableCopy];
  21. }
  22. if (oneCopy == nil) {
  23. oneCopy = [oneValue copy];
  24. }
  25. [ret setValue:oneCopy forKey:key];
  26. }
  27. return ret;
  28. }
  29. @end

使用类别方法来实现。

自定义对象 

如果是我们定义的对象,那么我们自己要实现NSCopying,NSMutableCopying这样就能调用copy和mutablecopy了。举个例子:

  1. @interface MyObj : NSObject<nscopying ,NSMutableCopying>
  2. {
  3. NSMutableString *name;
  4. NSString *imutableStr;
  5. int age;
  6. }
  7. @property (nonatomic, retain) NSMutableString *name;
  8. @property (nonatomic, retain) NSString *imutableStr;
  9. @property (nonatomic) int age;
  10. @end
  11. @implementation MyObj
  12. @synthesize name;
  13. @synthesize age;
  14. @synthesize imutableStr;
  15. - (id)init
  16. {
  17. if (self = [super init])
  18. {
  19. self.name = [[NSMutableString alloc]init];
  20. self.imutableStr = [[NSString alloc]init];
  21. age = -1;
  22. }
  23. return self;
  24. }
  25. - (void)dealloc
  26. {
  27. [name release];
  28. [imutableStr release];
  29. [super dealloc];
  30. }
  31. - (id)copyWithZone:(NSZone *)zone
  32. {
  33. MyObj *copy = [[[self class] allocWithZone:zone] init];
  34. copy->name = [name copy];
  35. copy->imutableStr = [imutableStr copy];
  36. // copy->name = [name copyWithZone:zone];;
  37. // copy->imutableStr = [name copyWithZone:zone];//
  38. copy->ageage = age;
  39. return copy;
  40. }
  41. - (id)mutableCopyWithZone:(NSZone *)zone
  42. {
  43. MyObj *copy = NSCopyObject(self, 0, zone);
  44. copy->name = [self.name mutableCopy];
  45. copy->ageage = age;
  46. return copy;
  47. }
  48. @end

小结:

对于非容器类对象,有:

如果对一个不可变对象复制,copy是指针复制,即浅拷贝;而mutableCopy则是对象复制,即深拷贝。(示例1)

如果是对可变对象复制,都是深拷贝,但copy复制返回的对象是不可变的。(示例2)

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 枕巾上的头油怎么办 洗手盆缝隙漏水怎么办 洗手盆裂缝漏水怎么办 洗手盆堵了怎么办 征信账号注册怎么办 注册不了征信号怎么办 阿里巴巴一键铺货到淘宝发货怎么办 淘宝购物的问题怎么办 买家评价被删除怎么办 淘宝订单虚假交易怎么办 被判定虚假物流怎么办 淘宝有虚假交易怎么办 微信辅助不了怎么办 微信验证失败怎么办 淘宝占空间太大怎么办 淘宝占用空间大怎么办 ipad空间不够用怎么办 ipadmini密码忘了怎么办 旧ipad特别卡怎么办 苹果ipad反应慢怎么办 手机垃圾多了怎么办 ipad2内存过低怎么办 苹果平板ipad内存不足怎么办 手机dns配置错误怎么办 蓝牙已停止运行怎么办 ipad看电视闪退怎么办 ipad为什么看电视会闪退怎么办 微淘直播延迟怎么办 手机淘宝进群领金币怎么办 做淘客冲销量停止淘客后怎么办 微信中零钱提现怎么办 淘宝买家不签收怎么办 小龙虾没人下单怎么办 淘宝直播不浮现怎么办 淘宝直播看不了怎么办 理财客户说没钱怎么办 投资不给钱了怎么办 工作中遇到挫折怎么办 手机qq出现异常怎么办 农行卡出现异常怎么办 淘宝长期不发货怎么办