博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
iOS开发那些事儿(五)Objective-C浅拷贝与深拷贝
阅读量:7058 次
发布时间:2019-06-28

本文共 7458 字,大约阅读时间需要 24 分钟。

  1. 浅拷贝:copy操作出来的对象指针直接指向模板的地址。即两个对象公用一块内存地址
    1 #import 
    2 int main(int argc, const char * argv[]) { 3 @autoreleasepool { 4 NSString * testStr = @"connor"; 5 NSLog(@"testStr's Address = %p",testStr); 6 7 NSString * testStrCopy = [testStr copy]; 8 NSLog(@"testStrCopy Address = %p",testStrCopy); 9 10 NSArray * array = @[@1,@2,@3];11 NSLog(@"array Address = %p",array);12 13 NSArray * copyArray = [array copy];14 NSLog(@"copyArray Address = %p",copyArray);15 }16 return 0;17 }

    输出结果如下:

    DataStruct[11210:2189074] testStr's Address      = 0x100004280

    DataStruct[11210:2189074] testStrCopy Address = 0x100004280

    DataStruct[11210:2189074] array Address            = 0x100300650

    DataStruct[11210:2189074] copyArray Address     = 0x100300650

  2. 深拷贝:copy操作出来的对象指针直接指向新开辟的内存。即持有原对象的拷贝副本
    1 #import 
    2 #import "Father.h" 3 int main(int argc, const char * argv[]) { 4 @autoreleasepool { 5 NSString * test = @"a"; 6 NSLog(@"%p",test); 7 8 NSString * testCopy = [test mutableCopy]; 9 NSLog(@"%p",testCopy);10 }11 return 0;12 }

    输出结果如下:

    DataStruct[11355:2249168] 0x100004280

    DataStruct[11355:2249168] 0x100203cf0

  3. Foundation总结大致如下
    •   NS*类型的类调用Copy属于浅拷贝(例如NSString、NSArray等等)
    •   NS*类型的类调用MutableCopy属于深拷贝(例如NSString、NSArray等等)
    •   NSMutable*类型无论调用Copy或者MutableCopy都属于深拷贝
  4. 拷贝构造:以上我们谈的都是Foundation中用到的深浅拷贝,如果我们自己定义了一个类。怎么去实现它的深浅拷贝呢?这里就要用到拷贝构造方法。iOS中默认NSObject是不遵循NSCopying(不变副本)、NSMutableCopying(可变副本)的,所以如果想一个对象可Copy,就必须实现其中两个协议并且重写copyWithZone、mutableCopyWithZone方法。
    •   下面我们定义一个Father类,来实现深拷贝:
      1 /** .h  */ 2 #import 
      3 @interface Father : NSObject
      4 @property(nonatomic,copy)NSString * name; 5 @end 6 7 /** .m */ 8 #import "Father.h" 9 10 @implementation Father11 -(id)copyWithZone:(NSZone *)zone{12 Father * copyFather = [[self class]allocWithZone:zone];13 return copyFather;14 }15 @end

      写好了Father类我们在外界就可以利用copy的方法去copy出一个Father对象

      1 #import 
      2 #import "Father.h" 3 int main(int argc, const char * argv[]) { 4 @autoreleasepool { 5 Father * fatherA = [[Father alloc]init]; 6 fatherA.name = @"connor"; 7 NSLog(@"%p",fatherA); 8 9 Father * fatherB = [fatherA copy];10 NSLog(@"%@",fatherB.name);11 NSLog(@"%p",fatherB);12 }13 return 0;14 }

      输出结果:

      DataStruct[11383:2256524] 0x100206c80

      DataStruct[11383:2256524] (null)

      DataStruct[11383:2256524] 0x100300600

      从输出结果来看,两个Father实例的内存地址是不一样的我们实现了深拷贝。但是为什么第二个Father没有名字?在拷贝过程过虽然我是从你FatherA拷贝过来的,但是你并没有指定FatherA中的属性到底是什么方式拷贝过来。所以这里面如果想要实现名字也拷贝过来,需要我们自己去定义到底是深拷贝过来还是浅拷贝过来。这也符合苹果做事的风格嘛。

      1 #import "Father.h"2 //添加name的浅拷贝3 @implementation Father4 -(id)copyWithZone:(NSZone *)zone{5     Father * copyFather = [[self class]allocWithZone:zone];6     copyFather.name     = [self.name copy]; //如果想要深拷贝过来直接mutableCopy即可7     return copyFather;8 }9 @end

      结果输出两个name的内存地址:

      DataStruct[11409:2261412] 0x100004290

      DataStruct[11409:2261412] 0x100004290

    • 现在情况改变了,Father平时出门需要开车。Father需要持有Car类。那这个时候我们要如果复制这个爸爸!(因为复制出来的Father不能和之前那个Father开一辆车,所以我们应该用深拷贝。过程很简单直接贴代码了!)
      1 /** .h */ 2 #import 
      3 4 @interface Car : NSObject
      5 @property(nonatomic,copy)NSString * brand; 6 @end 7 8 /** .m */ 9 @implementation Car10 -(id)copyWithZone:(NSZone *)zone{11 Car * copyCar = [[self class]allocWithZone:zone];12 copyCar.brand = [self.brand mutableCopy];13 return copyCar;14 }15 @end
      Car
      /** .h */#import 
      #import "Car.h"@interface Father : NSObject
      @property(nonatomic,copy)NSString * name;@property(nonatomic,strong)Car * car;@end/** .m */#import "Father.h"@implementation Father-(id)copyWithZone:(NSZone *)zone{ Father * copyFather = [[self class]allocWithZone:zone]; copyFather.name = [self.name copy]; copyFather.car = [self.car copy]; return copyFather;}@end
      Father
      #import 
      #import "Father.h"#import "Car.h"int main(int argc, const char * argv[]) { @autoreleasepool { Father * fatherA = [[Father alloc]init]; fatherA.car = [[Car alloc]init]; NSLog(@"%p",fatherA.car); Father * fatherB = [fatherA copy]; NSLog(@"%p",fatherB.car); } return 0;}
      main

      输出结果:

      DataStruct[11441:2268004] 0x100111f60

      DataStruct[11441:2268004] 0x1001154a0

    • copy这种操作如果发生在继承关系之后就有什么样的效果?或者说1.父类实现了NSCopying,子类该如果实现NSCopying。2.父类没有实现NSCopying,子类如何实现NSCopying?要接一个问题我们先看下表象是什么,然后通过表象来分析问题并解决问题。接下来我们先试着用第一种情况来看看表象:Son继承于Father
      1 /** .h */ 2 #import "Father.h" 3 @interface Son : Father 4 @property(nonatomic,copy)NSString * toy; 5 @end 6  7 /** .m */ 8 #import "Son.h" 9 @implementation Son10 @end
      Son
      1 #import 
      2 #import "Son.h" 3 int main(int argc, const char * argv[]) { 4 @autoreleasepool { 5 Son * sonA = [[Son alloc]init]; 6 sonA.name = @"connor"; 7 sonA.toy = @"iPhone"; 8 9 Son * sonB = [sonA copy];10 11 NSLog(@"sonA's Address = %p",sonA);12 NSLog(@"sonB's Address = %p",sonB);13 14 NSLog(@"sonA's name Address = %p",sonA.name);15 NSLog(@"sonB's name Address = %p",sonB.name);16 17 NSLog(@"sonA's toy Address = %p",sonA.toy);18 NSLog(@"sonB's toy Address = %p",sonB.toy);19 }20 return 0;21 }
      main

      输出结果:

      DataStruct[11563:2279201] sonA's Address      = 0x100114bc0

      DataStruct[11563:2279201] sonB's Address          = 0x100111f70

      DataStruct[11563:2279201] sonA's name Address = 0x100004260

      DataStruct[11563:2279201] sonB's name Address = 0x726f6e6e6f6365

      DataStruct[11563:2279201] sonA's toy Address    = 0x100004280

      DataStruct[11563:2279201] sonB's toy Address = 0x0                                                                                  这个结果也在我们意料之内的嘛,Son是继承与Father类的,Father实现了Copy协议,所以这个copy协议实现会继承到子类。我的理解其实:当Son调用Copy方法的时候就将消息转发给Son抽象类,发现Son中没有实现Copt则向Father发送消息SuperSendMsg就相当于事件响应链传递一样。一直向上传递直到能被处理。**这里需要注意一点Father中  Father * copyFather = [[self class]allocWithZone:zone];这里用的是self而不是Father因为Son会走到这里来,我们不能限制死到底是谁来调用***。接下来我们继续看为什么toy是个空置,这个原因和上面说的嵌套copy有点类似。因为Father不清楚你Son的属性到底是怎么copy过来的。那么怎么修改呢?我们只要在toy中稍作修改即可

      1 @implementation Son2 -(id)copyWithZone:(NSZone *)zone{3      //这句话保证父类的copy也被call到4     Son * son = [super copyWithZone:zone];5     son.toy   = [self.toy mutableCopy];6     return son;7 }8 @end
      Son

      输出结果:toy成功被深拷贝

      DataStruct[11606:2301994] sonA's toy Address = 0x100004288

      DataStruct[11606:2301994] sonB's toy Address = 0x656e6f68506965

    • 接下来我们看一下第二种情况,父类没有实现NSCopying,子类如何实现NSCopying。直接让子类去实现就好了呗。父类如果需要深拷贝的我延迟到子类去执行呗!(这里有个问题,我的Son没有继承NSCopying,但是重写CopyWithZone居然没有报错??!!)
      1 #import "Son.h" 2 @implementation Son 3 -(id)copyWithZone:(NSZone *)zone{ 4 //    Son * son = [super copyWithZone:zone]; 5     Son * son = [[self class] allocWithZone:zone]; 6     son.name  = [self.name mutableCopy]; 7     son.toy   = [self.toy mutableCopy]; 8     return son; 9 }10 @end
      Son

      输出结果:

      DataStruct[11660:2317623] sonA's Address          = 0x100206e00 

      DataStruct[11660:2317623] sonB's Address          = 0x1002040e0

      DataStruct[11660:2317623] sonA's name Address = 0x100004260

      DataStruct[11660:2317623] sonB's name Address = 0x726f6e6e6f6365

      DataStruct[11660:2317623] sonA's toy Address    = 0x100004280

      DataStruct[11660:2317623] sonB's toy Address    = 0x656e6f68506965

转载于:https://www.cnblogs.com/conorBlogs/p/5535256.html

你可能感兴趣的文章
macbook 一些php相关操作
查看>>
URAL 1995 Illegal spices
查看>>
POJ 2516 Minimum Cost
查看>>
for循环工作原理
查看>>
Chrome提示:"请停用以开发者模式运行的扩展程序"的解决办法
查看>>
day03-Python基础
查看>>
编译cordova-android代码
查看>>
解决网络不可用--Using_Service_Workers
查看>>
Microsoft UDDI安装手记
查看>>
网站里的各种职位名称
查看>>
jenkins集成错误 ...
查看>>
POJ 3277 线段树+扫描线
查看>>
Mycat实现读写分离
查看>>
openlayer geoserver 实现wfs 的更新
查看>>
基于C语言的UTF-8中英文替换密码设计
查看>>
Swift笔记2
查看>>
【编程之美】中国象棋将帅问题
查看>>
【算法学习笔记】38.最短路问题 SJTU OJ 1105 path
查看>>
C++中不常用关键字
查看>>
洛谷P3723 礼物
查看>>