Object-C中对自定义类实现<NSCopying>协议

来源:互联网 发布:淘宝买家最高等级是谁 编辑:程序博客网 时间:2024/04/28 14:24
如果尝试使用自定义类(例如,人类(person类)、地址簿类(myBook类)、分数类(Fraction类))中的copy方法,如

[cpp] view plaincopy
  1. myBook = [myBook mutableCopy];  
  2. person = [Person copy];  
等类似的操作,将会收到一条异常出错的消息,它可能如下所示:

-[Fraction copyWithZone:]: unrecognized selector sent to instance 0x7fabb8414380

这种错误,是对于自定义类,要实现使用自己的类进行复制,必须根据<NSCopying>协议实现其中的一两个方法。

下面将展示如何为自定义的分数类(Fraction类)添加copy方法。注意:这里描述的复制策略的技巧非常适合于你自己定义的类。如果这些类是任何Foundation类的子类,那么可能需要实现较为复杂的复制策略。必须考虑这样一个事实:超类可能已经实现了它自己的复制策略。

实现<NSCopying>协议时,类必须实现copyWithZone:方法来响应copy消息。(这条copy消息仅将一条带有nil参数的copyWithZone:消息发送给你的类)。注意,如果想要区分可变副本和不可变副本,那么copyWithZone:应该返回不可变副本,而mutableCopyWithZone:应该返回可变副本。产生对象的可变副本并不要求被复制的对象本身也是可变的(反之亦然),想要产生不可变副本的可变副本是很合理的(例如,字符串对象)。

在Fraction.h文件中如下所示:(其中Fraction是NSObject的子类,并且符合NSCopying协议)

[cpp] view plaincopy
  1. #import <Foundation/Foundation.h>  
  2.   
  3. @interface Fraction : NSObject<NSCopying>  
  4. {  
  5.     int a, b;  
  6. }  
  7.   
  8. @property int a, b;  
  9.   
  10. -(void)setTo:(int) a over: (int) b;  
  11. -(void)print;  
  12.   
  13. @end  

在实现文件Fraction.m中,为新方法添加如下定义:

[cpp] view plaincopy
  1. #import "Fraction.h"  
  2.   
  3. @implementation Fraction  
  4.   
  5. @synthesize a,b;  
  6.   
  7. -(void)setTo:(int) aa over: (int) bb  
  8. {  
  9.     a = aa;  
  10.     b = bb;  
  11. }  
  12.   
  13. -(void)print  
  14. {  
  15.     NSLog(@"%i/%i",a, b);  
  16. }  
  17.   
  18. //实现NSCopying协议的方法,来使此类具有copy功能  
  19. -(id)copyWithZone:(NSZone *)zone  
  20. {  
  21.     Fraction *newFract = [[Fraction allocWithZone:zone] init];  
  22.       
  23.     [newFract setTo:a over:b];  
  24.       
  25.     return newFract;  
  26. }  
  27.   
  28. @end  

在文件main.m中对于上述类的测试代码如下:

[cpp] view plaincopy
  1. #import <Foundation/Foundation.h>  
  2. #import "Fraction.h"  
  3.   
  4. int main(int argc, const char * argv[])  
  5. {  
  6.   
  7.     @autoreleasepool {  
  8.   
  9.         Fraction *f1 = [[Fraction alloc] init];  
  10.         Fraction *f2;  
  11.           
  12.         [f1 setTo:2 over:5];  
  13.           
  14.         f2 = [f1 copy];   
  15.           
  16.         [f2 setTo:1 over:3];  
  17.           
  18.         [f1 print];  
  19.         [f2 print];  
  20.           
  21.         [f1 release];  
  22.         [f2 release];  
  23.           
  24.     }  
  25.     return 0;  
  26. }  


由此可以实现对自定义类Fraction类的拷贝,运行结果如下:

2/5

1/3

该程序创建了一个名为f1的Fraction对象并将其设置为2/5.然后,它调用copy方法来产生副本,copy方法向你的对象发送copyWithZone:消息,这个方法产生了一个新的Fraction,将f1的值复制到其中,并返回结果。回到main函数中,再将这个结果赋值给f2.随即,将f2中的值设置为分数1/3,这样就验证了这些操作对原始分数f1是没有影响的。

如果你的类可以产生子类,那么copyWithZone:方法将被继承。在这种情况下,该方法中的程序行:

[cpp] view plaincopy
  1. //无子类是可以这样实现  
  2.    Fraction *newFract = [[Fraction allocWithZone:zone] init];  

应该改为:

[cpp] view plaincopy
  1. //有子类时,需要这样实现  
  2.     Fraction *newFract = [[[self class] allocWithZone:zone] init];  

这样,可以从该类分配一个新的对象,而这个类的copy的接收着(例如,如果它产生了一个名为NewFraction 的子类,那么应该确保在继承的方法中分配了新的NewFraction对象,而不是Fraction对象)。

如果编写一个类的copyWithZone:方法,而该类的超类也实现了<NSCopying>协议,那么应该先调用超类的copy方法以复制继承来的实例变量,然后加入自己的代码以复制想要添加到该类中的任何附加的实例变量(如果有的话)。

你必须确定是否在类中实现浅复制或深复制,并为其编写文档,以告知类的其他使用者。

0 0
原创粉丝点击