




免费预览已结束,剩余18页可下载查看
下载本文档
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第18章复制对象 目录 18 1Copy和MutableCopy方法18 2浅复制和深复制18 3实现协议18 4用赋值方法和取值方法复制对象 18 1Copy和MutableCopy方法 Foudation类实现了名为copy和mutableCopy的方法 可以使用这些方法创建对象的副本 通过一个符合协议的方法来完成此任务 如果类必须区分要产生对象的是可变副本还是不可变副本 还需要根据协议实现一个方法 18 1Copy和MutableCopy方法 回顾Foundation类的copy方法 给定前面描述的两个NSMutableArray对象dataArray2和dataArray语句在内存中创建了一个新的dataArray副本 并复制了它的所有元素 随后 执行语句删除了dataArray2中的第一个元素 但却不删除dataArray中的元素 代码18 1说明了这个情况 dataArray2 dataArraymutableCopy dataArray2removeObjectAtIndex 0 Program18 1 import import import importintmain intargc char argv NSAutoreleasePool pool NSAutoreleasePoolalloc init NSMutableArray dataArray NSMutableArrayarrayWithObjects one two three four nil NSMutableArray dataArray2 simpleassignmentdataArray2 dataArray dataArray2removeObjectAtIndex 0 NSLog dataArray for NSString elemindataArray NSLog elem NSLog dataArray2 for NSString elemindataArray2 NSLog elem tryaCopy thenremovethefirstelementfromthecopy dataArray2 dataArraymutableCopy dataArray2removeObjectAtIndex 0 NSLog dataArray for NSString elemindataArray NSLog elem NSLog dataArray2 for NSString elemindataArray2 NSLog elem dataArray2release pooldrain return0 Program18 1OutputdataArray twothreefourdataArray2 twothreefourdataArray twothreefourdataArray2 threefour 该程序定义了可变数组对象dataArray 并分别将其元素设置为字符串对象 one two three four 前面讨论过 赋值语句dataArray2 dataArray 仅仅创建了对内存中同一个数组对象的另一个引用 从dataArray2中删除第一个对象并随后输出两个数组对象中的元素 不出意料 这两个引用中的第一个元素 字符串 one 都会消失 接下来 创建一个dataArray的可变副本并将它赋值给dataArray2的最终副本 这样在内存中创建了两个截然不同的可变数组 两者都包含三个元素 现在 删除dataArray2中的第一个元素 不会对dataArray的内容有任何影响 正如程序输出的最后两行验证一样 18 1Copy和MutableCopy方法 注意 产生一个对象的可变副本并不要求被复制的对象本身是可变的 这种情况同样适用于不可变副本 可以创建可变对象的不可变副本 还要注意在产生数组的副本时 数组中每个元素的保持计数将通过复制操作自动增1 因此 如果产生数组的副本并随即释放原始数组 那么副本仍然包含有效的元素 因为dataArray的副本是在程序中使用mutableCopy方法产生的 所以要负责释放它的内存 上一章讲述了释放自己使用的一个copy方法创建的对象这条规则 这解释了下面这个程序行 dataArray2release 的实质 18 2浅复制与深复制 代码清单18 1使用不可变字符串来填充dataArray的元素 常量字符串对象是不可变的 代码清单18 2中 将使用可变字符串代替它来填充数组 这样就可以改变数组中的一个字符串 Program18 2 import import import importintmain intargc char argv NSAutoreleasePool pool NSAutoreleasePoolalloc init NSMutableArray dataArray NSMutableArrayarrayWithObjects NSMutableStringstringWithString one NSMutableStringstringWithString two NSMutableStringstringWithString three nil NSMutableArray dataArray2 NSMutableString mStr NSLog dataArray for NSString elemindataArray makeacopy thenchangeoneofthestringsdataArray2 dataArraymutableCopy mStr dataArrayobjectAtIndex 0 mStrappendString ONE NSLog dataArray for NSString elemindataArray NSLog elem NSLog dataArray2 for NSString elemindataArray2 NSLog elem dataArray2release pooldrain return0 Program18 2OutputdataArray onetwothreedataArray oneONEtwothreedataArray2 oneONEtwothree 18 2浅复制与深复制 使用下面的语句检索dataArray的第一个元素 mStr dataArrayobjectAtIndex 0 然后 使用下面的语句将字符串 ONE 附加到这个元素 mStrappendString ONE 注意 原始数组及其副本中的第一个元素的值 它们都修改了 从集合中获取元素时 就得到了这个元素的一个新引用 但并不是一个新副本 所以 对dataArray调用objectAtIndex 方法时 返回的对象与dataArray中的第一个元素都指向内存中的同一个对象 随后 修改string对象mStr的副作用就是同时改变了dataArray的第一个元素 副本的第一个元素被改变的原因是默认的浅复制方式 它意味着使用mutableCopy方法复制数组时 在内存中为新的数组对象分配了空间 并且将单个元素复制到新数组中 然而将原始素组中的每个元素复制到新位置意味着 仅将引用从一个数组元素复制到另一个数组元素 这样做的最终结果 就是这两个数组中的元素都指向内存中的一个字符串 18 2浅复制与深复制 要为数组中每个元素创建完全不同的副本 需要执行所谓的深复制 这就意味着要创建数组中的每个对象内容的副本 而不仅是这些对象的引用的副本 并且考虑一下 如果一个数组中的元素本身是数组对象时 深复制意味着该如何处理 然而使用Foundation类的copy或mutableCopy方法时 深复制并不是默认执行的 18 3实现协议 如果尝试使用自己类 例如地址薄 中的copy方法 如下所示 NewBook myBookmutableCopy 将会收到如下错误信息 AddressBookcopyWithZone selectornotrecognized Uncaughtexception AddressBookcopyWithZone selectornotrecognized正如提示 要实现使用自己的类进行复制 必须根据协议实现其中一两个方法 我们将展示如何为Fraction类添加copy方法 注意 这里描述的复制策略的技巧非常适合用于你自己的类 如果这些类是Foundation类的子类 可能需要较复杂的复制策略 超类可能已经实现了它自己的复制策略 要产生Fraction类的一个对象的副本 需要分配一个新分数空间并简单将这两个整数复制到新分数中 18 3实现协议 实现协议时 类必须实现copyWithZone 方法来响应copy消息 这条copy消息仅将一条带有nil参数的copyWithZone 消息发送给你的类 注意 如果想要区分可变副本和不可变副本 还需要根据协议实现mutableCopyWithZone 方法 如果两个方法都实现 那么copyWithZone 应该返回不可变副本 而mutableCopytWithZone 将返回可变副本 产生对象的可变副本并不要求被复制的对象本身也是可变的 反之亦然 想要产生不可变对象的可变副本是很合理的 例如 考虑字符串对象 interface指令应该如下所示 interfaceFraction NSObjectFraction是NSObject的子类 并且符合NSCopying协议 在实现文件Fraction m中 为新方法添加下列定义 id copyWithZone NSZone zone Fraction newFract FractionallocWithZone zone init newFractsetTo numeratorover denominator returnnewFract 参数zone与不同的存储区有关 你可以在程序中分配并使用这些存储区 只有在编写要分配大量内存的应用程序并且想要通过将空间分配分组到这些存储区中来优化内存分配时 才需处理这些zone 可以使用传递给copyWithZone 的值 并将它传给名为allocWithZone 的内存分配方法 这个方法在制定存储区中分配内存 分配新的Fraction对象后 将接受者的numerator和denominator变量复制到其中 copyWithZone 方法应该返回对象的新副本 这个对象就是在你的方法中实现的 代码18 3测试了你的新方法 Program18 3 Copyingfractions import Fraction h importintmain intargc char argv NSAutoreleasePool pool NSAutoreleasePoolalloc init Fraction f1 Fractionalloc init Fraction f2 f1setTo 2over 5 f2 f1copy f2setTo 1over 3 f1print f2print f1release f2release pooldrain return0 Program18 3Output2 51 3 该程序调用copy方法来产生副本 copy方法向你的对象发送copyWithZone 消息 这个方法产生了一个新Fraction 将f1的值复制到其中 并返回结果 返回main中 将该结果赋给f2 随后 将f2的值置为1 3 将f2 f1copy 改为 f2 f1 并在程序结尾删除f2的release语句 可以获得不同结果 如果你的类可以产生子类 那个copyWithZone 方法将被继承 那么 该方法中的程序行Fraction newFract FractionallocWithZone zone init 需要改成Fraction newFract selfclass allocWithZone zone init 这样 可以从该类分配一个新对象 而这个类是copy的接受者 例如 它产生了一个NewFraction的子类 那么应该确保在继承的方法中分配了新的NewFraction对象 而不是Fraction对象 如果编写一个类的copyWithZone 方法 而该类的超累也实现了协议 那么先调用超类的copy方法来复制继承来的实例变量 然后假如自己的代码以复制想要添加到该类中的任何实例变量 18 4用赋值方法和取值方法复制对象 只要实现赋值方法或取值方法 都应该考虑实例变量中存储的内容 要检索的内容以及是否需要保护这些值 例如 考虑使用setName 方法来设置AddressCard对象的名称时 newCardsetName newName 假设newName是一个字符串对象 它包含新地址卡片的名称 假定在赋值方法例程内 你只是简单地将参数赋值给相应的实例变量 void setName NSString theName name theName 18 4用赋值方法和取值方法复制对象 现在 如果随后更改了程序的newName中包含的一些字符 那么你认为会发生什么 对 这样也会无意间改变地址卡片中对应的域 因为它们都引用相同的string对象 前面已经学过 为了避免无意间对程序产生影响 比较安全的途径是在赋值方法例程中产生对象的副本 通过使用alloc方法来创建新的string对象 然后使用initWithString函数将该方法提供的参数值赋给它 可以实现在赋值对象中产生副本 18 4用赋值方法和取值方法复制对象 还可以编写如下的setName 方法来使用copy 当然 要使赋值方法例程的内存管理友好一些 首先应该自动释放旧的值 如下所示 void setName NSString theName name theNamecopy void setName NSString theName nameautorelease name theNamecopy 18 4用赋值方法和取值方法复制对象 如果在属性声明中为实例变量指定了copy属性 那么合并后的方法会使用类的copy方法 你编写的copy方法或继承的copy方法 所以下列property声明 property nonatomic copy NSString name 会生成一个合并的方法 其行为类似于 void setName NSString theName if theName name namerelease name theNamecopy 18 4用赋值方法和取值方法复制对象 此处使用n
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 储能电站火灾救援课件
- 人力资源总监职位聘用合同修订与激励方案
- 生物质能源项目融资咨询与生物质利用技术支持协议
- 民宿退订合同范本:特色民宿住宿服务退房协议
- 城郊集体土地厂房开发建设及经营权转让合同
- 自然人独资公司股权激励及合伙人权益保护协议
- 韩国韩娱离婚协议及子女抚养权、赡养费协议
- 智能家居解决方案项目合作投资战略协议书
- 公寓退房协议书范本:精装公寓房间退订服务细则
- 信息技术预制场地租赁及云计算服务合同
- (2024年)知识产权全套课件(完整)
- 阀门试压方案样本
- 电力线路保护工作手册样本
- 儿内科内分泌疾病诊疗规范2023版
- 十大医药代表成功经验分享
- 2022年上海市浦东新区6月线下高考二模英语试题(含答案和听力音频与听力稿)
- 人脸识别系统软件使用手册
- 竣工验收证书(样本)
- 婴幼儿大便问题全解析
- 统编版三年级上册《快乐读书吧》阅读测试题
- 沉降观测记录表(标准版)
评论
0/150
提交评论