三、实现对象的拷贝
对于我们自己创建的类来说,如果需要实现对象的拷贝,则需要实现NSCopying协议或者NSMutableCopying协议。前者用于实现对象拷贝,而后者则通常会返回一个可以进行修改的对象副本,例如Foundation框架中的常用容器类NSArray、NSSet等。这两个协议定义如下:
@protocol NSCopying
- (id)copyWithZone:(NSZone *)zone;
@end
@protocol NSMutableCopying
- (id)mutableCopyWithZone:(NSZone *)zone;
@end
copy方法与mutableCopy方法分别会调用copyWithZone:方法与mutableCopyWithZone:方法,并传入nil。将代码修改如下:
int main(int argc, const char * argv[])
{
@autoreleasepool
{
TestObject* to1 = [[[TestObject alloc] init] autorelease];
to1->x = 100; to1->y = 50;
TestObject* to2 = [to1 copy];
NSLog(@"to2: %@", to2);
}
return 0;
}
程序编译通过,但运行时抛出异常:
-[TestObject copyWithZone:]: unrecognized selector sent to instance 0x10e2141b0
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[TestObject copyWithZone:]: unrecognized selector sent to instance 0x10e2141b0'
原因是TestObject类尚未遵从NSCopying,因此无法进行拷贝。将TestObject类修改如下:
@interface TestObject : NSObject <NSCopying>
{
@public
int x;
int y;
}
@end
@implementation TestObject
- (NSString*)description
{
return [NSString stringWithFormat:@"%@: %p, x: %d, y: %d", [self class], self, x, y];
}
- (id)copyWithZone:(NSZone *)zone
{
TestObject* newTestObject = [[TestObject allocWithZone:zone] init];
newTestObject->x = self->x;
newTestObject->y = self->y;
return newTestObject;
}
@end
再次编译运行,这一次运行正常,输出如下结果:
to2: TestObject: 0x7ffaa84141c0, x: 100, y: 50
注意,copyWithZone:方法调用allocWithZone:方法申请了内存空间并创建了一个新的对象,因此调用copy或者mutableCopy的代码需要对拷贝的对象进行内存的释放操作,忘记释放会导致内存泄漏。