深浅拷贝

关于Copy的使用

1.在OC中,copy是利用一个源对象产生一个副本对象,本质就是修改源对象的属性和行为,不会影响副本对象,同样,修改副本对象的属性和行为,不会影响源对象。

2.如何使用copy

  • 一个对象可以调用copy或mutableCopy方法来创建一个副本对象
  • copy:创建的是不可变副本(NSString、NSArray、NSDictionary…)
  • mutableCopy:创建的是可变副本(如NSMutableString、NSMutableArray、NSMutableDictionary…)

3.copy使用的前提
必须遵守NSCopying协议,实现copyWithZone:方法

@protocol NSCopying
- (id)copyWithZone:(NSZone *)zone;
@end

4.mutableCopy的使用前提
必须遵守NSMutableCopying协议,实现mutableCopyWithZone:方法

@protocol NSMutableCopying
- (id)mutableCopyWithZone:(NSZone *)zone;
@end

深浅复制

  • 先来形象解释一波

解释1
浅拷贝:如果拷贝一个对象,而不拷贝它的子对象;
深拷贝:拷贝一个对象时连同子对象一起拷贝
解释2
浅拷贝:向retain一样,创建一个指针指向了同一块内存空间(即同一个对象,不产生新对像),使该内存空间引用计数加1
深拷贝:向copy一样,复制一个对象,产生了一个新的对象;新对象的引用计数为1,旧对象的引用计数不变

补充:深拷贝用归档和解归档可以实现
例子:人---关联一个车---车再关联一个引擎
应用场景:用初始化alloc init 创建对象,速度慢,内存...;
所以考虑用复制对象方式来创建

1.浅复制(浅拷贝,指针拷贝,shallow copy)

  • 源对象和副本对象是同一个对象
  • 源对象(副本对象)引用计数器+1,相当于做一次retain操作
  • 本质:没有产生新的对象
NSString *srcStr = @"1gcode";
NSString *copyStr = [srcStr copy];
NSLog(@"srcStr = %p, copyStr = %p", srcStr, copyStr);

2.深复制(深拷贝,内容拷贝,deep copy)

  • 源对象和副本对象是不同的两个对象
  • 源对象引用计数器不变,副本对象计数器为1(因为是新产生的)
  • 本质:产生了新的对象
NSString *srcStr = @"1gcode";
NSMutableString *copyStr = [srcStr mutableCopy];
NSLog(@"src = %p, copy = %p", srcStr, copyStr);
NSLog(@"src = %@, copy = %@", srcStr, copyStr);
[copyStr appendString:@" cool"];
NSLog(@"src = %@, copy = %@", srcStr, copyStr);
NSMutableString *srcStr = [NSMutableString stringWithFormat:@"1gcode"];
NSString *copyStr = [srcStr copy];
[srcStr appendString:@".com"];
NSLog(@"src = %p, copy = %p", srcStr, copyStr);
NSLog(@"src = %@, copy = %@", srcStr, copyStr);
NSMutableString *srcStr = [NSMutableString stringWithFormat:@"1gcode"];
NSMutableString *copyStr = [srcStr mutableCopy];
[srcStr appendString:@".com"];
[copyStr appendString:@" good"];
NSLog(@"src = %p, copy = %p", srcStr, copyStr);
NSLog(@"src = %@, copy = %@", srcStr, copyStr);
总结

1.浅拷贝是指针的拷贝,深拷贝是地址的拷贝

2.就是有可变的就是深拷贝;比如[NSString mutableCopy]这种就是深拷贝,[NSMutableString copy]也是深拷贝

3.可变就是要保留原有的对象,操作copy出来的对象,这两个对象的指针指向两个地址;这样做目的是保证原来的对象不被修改(如果你原来的对象都改了,你原来的对象本来要干的东西就干不了了)

4.浅拷贝不会拷贝地址只会拷贝指针,如果你要修改对象的内容,那你以前的那个对象也被修改了

5.浅复制好比你和你的影子,你完蛋,你的影子也完蛋;深复制好比你和你的克隆人,你完蛋,你的克隆人还活着

3.copy与内存管理

1.如果是浅拷贝,不会生成新的对象,但是系统就会对原来的对象进行retain,所以我们要对原来的对象进行一次
2.如果是深拷贝,会生成新的对象,系统不会对原来的对象进行retain,但是因为生成了新的对象,所以我们要对新的对象进行release

  • 对于浅拷贝
    原对象引用计数器+1,必须释放原对象
NSString *srcStr = [[NSString alloc] initWithFormat:@"www.1gcode.com"];
NSLog(@"srcStr = %lu", [srcStr retainCount]);
NSString *copyStr = [srcStr copy];
NSLog(@"copyStr = %lu", [copyStr retainCount]);
[copyStr release]; // 必须做一次release
  • 对于深拷贝(即深复制)
    新对象引用计数器+1,必须释放新对象
NSString *srcStr = [[NSString alloc] initWithFormat:@"www.1gcode.com"];
    NSLog(@"srcStr = %lu", [srcStr retainCount]);
    NSString *copyStr = [srcStr mutableCopy];
    NSLog(@"copyStr = %lu", [copyStr retainCount]);
    [copyStr release]; // 必须做一次release
  • copy与@property

1.@property使用copy可以防止外界修改内部的数据
2.可以使用copy保存block, 这样可以避免在block中使用的外界对象的时候, 外界的对象已经释放出现的野指针错误
3.注意: copy block可能会引发循环引用,如果对象中的block又用到了对象自己, 那么为了避免内存泄露, 应该将对象修饰为__block

你可能感兴趣的:(深浅拷贝)