三、實現對象的拷貝
對於我們自己創建的類來說,如果需要實現對象的拷貝,則需要實現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的代碼需要對拷貝的對象進行內存的釋放操作,忘記釋放會導致內存泄漏。