首先,objetive-c中有NSCopying 和NSMutableCopying 两种协议,分别声明了copyWithZone和mutableCopyWithZone方法。协议:就是把若干类中具有相同功能的方法都抽象出来,定义在一起。因此任何需要copy操作的类,只需要遵从NSCopying 和NSMutableCopying协议,并实现copyWithZone和mutableCopyWithZone方法,实现对象的拷贝。
其次,方法copy生成不可修改的对象,方法mutableCopy生成可修改的对象.生成是否可修改的对象跟之前拷贝的对象是否可修改没有关系,跟调用copy还是mutablecopy有关系。
@interface LOCBird : NSObject
{
NSString* name_;
}
@end
@implementation LOCBird
- (id)init
{
self = [super init];
if (self)
{
name_ = [[NSString alloc] initWithString:@"I am a Bird!!"];
}
return self;
}
- (void)dealloc
{
[name_ release];
[super dealloc];
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
NSMethodSignature* signature = [super methodSignatureForSelector:aSelector];
if (signature==nil)
{
signature = [name_ methodSignatureForSelector:aSelector];
}
NSUInteger argCount = [signature numberOfArguments];
for (NSInteger i=0 ; i<argCount ; i++)
{
NSLog(@"%s" , [signature getArgumentTypeAtIndex:i]);
}
NSLog(@"returnType:%s ,returnLen:%d" , [signature methodReturnType] , [signature methodReturnLength]);
NSLog(@"signature:%@" , signature);
return signature;
}
- (void)forwardInvocation:(NSInvocation *)anInvocation
{
NSLog(@"forwardInvocation:%@" , anInvocation);
SEL seletor = [anInvocation selector];
if ([name_ respondsToSelector:seletor]) {
[anInvocation invokeWithTarget:name_];
}
}
@end
LOCBird* bird1 =[[LOCBird alloc] init];
LOCBird* bird2 = [bird1 copy];
LOCBird* bird3 = [bird1 mutableCopy];
NSLog(@"%@ %@",bird2 , NSStringFromClass([bird2 class]));
NSLog(@"%@ %@",bird3 , NSStringFromClass([bird3 class]));
2012-03-22 22:17:28.384 LOCMessageForward[1082:f803] @
2012-03-22 22:17:28.385 LOCMessageForward[1082:f803] :
2012-03-22 22:17:28.385 LOCMessageForward[1082:f803] ^{_NSZone=}
2012-03-22 22:17:28.386 LOCMessageForward[1082:f803] returnType:@ ,returnLen:4
2012-03-22 22:17:28.387 LOCMessageForward[1082:f803] signature:<NSMethodSignature: 0x685ae90>
2012-03-22 22:17:28.388 LOCMessageForward[1082:f803] forwardInvocation:<NSInvocation: 0x6a45670>
2012-03-22 22:17:28.389 LOCMessageForward[1082:f803] @
2012-03-22 22:17:28.390 LOCMessageForward[1082:f803] :
2012-03-22 22:17:28.391 LOCMessageForward[1082:f803] ^{_NSZone=}
2012-03-22 22:17:28.392 LOCMessageForward[1082:f803] returnType:@ ,returnLen:4
2012-03-22 22:17:28.393 LOCMessageForward[1082:f803] signature:<NSMethodSignature: 0x685ae90>
2012-03-22 22:17:28.393 LOCMessageForward[1082:f803] forwardInvocation:<NSInvocation: 0x68438b0>
2012-03-22 22:17:28.394 LOCMessageForward[1082:f803] I am a Bird!! __NSCFConstantString
2012-03-22 22:17:28.395 LOCMessageForward[1082:f803] I am a Bird!! __NSCFString
因为LOCBird为遵从NSCopying 或NSMutableCopying 协议,所以不能响应copy消息,但由于重载了methodSignatureForSelector和forwardInvocation,实现将消息转发给NSString的name_成员,因此最后拷贝生成的NSString对象。
修改后遵从NSCopying 或NSMutableCopying 协议,输出如下:
2012-03-22 22:41:09.438 LOCMessageForward[1196:f803] <LOCBird: 0x6a6c760> LOCBird
2012-03-22 22:41:09.439 LOCMessageForward[1196:f803] <LOCBird: 0x687c880> LOCBird
最后测试NSString和NSarray的拷贝方法
<span style="white-space:pre"> </span>NSString* str1 = @"hello";
NSString* str2 = @"hello";
NSString* str3 = [NSString stringWithString:@"hello"];
NSString* str4 = [NSString stringWithFormat:@"hello"];
NSString* str5 = [[NSString alloc]initWithString:@"hello"];
NSString* str6 = [[NSString alloc]initWithFormat:@"hello"];
NSString* str7 = [NSString stringWithCString:"hello" encoding:NSUTF8StringEncoding];
NSString* str8 = [NSString stringWithCString:"hello" encoding:NSUTF8StringEncoding];
NSLog(@"%p,%p,%p,%p,%p,%p,%p,%p",str1,str2,str3,str4,str5,str6,str7,str8);
NSString* cpStr1 = [str1 copy];
NSMutableString* cpStr2 = [str1 mutableCopy];
NSLog(@"cpStr1=%p mutCpStr1=%p",cpStr1 , cpStr2);
NSArray* array = [NSArray arrayWithObjects:str1,str2,str3,str4,str5,str6,str7,str8,nil];
NSArray* imArray = [array copy];
for (NSString* str in imArray) {
NSLog(@"%p %@",str,str);
}
NSLog(@"-----------------");
NSMutableArray* mutArray = [array mutableCopy];
[mutArray addObject:@"hello"];
for (NSString* str in mutArray) {
NSLog(@"%p %@",str,str);
}
输出结果如下:
0x4640,0x4640,0x4640,0x6a69860,0x4640,0x6a65a50,0x6a6b7a0,0x6a6aec0
2012-03-22 22:41:06.906 LOCMessageForward[1196:f803] cpStr1=0x4640 mutCpStr1=0x68695f0
2012-03-22 22:41:06.906 LOCMessageForward[1196:f803] 0x4640 hello
2012-03-22 22:41:06.907 LOCMessageForward[1196:f803] 0x4640 hello
2012-03-22 22:41:06.907 LOCMessageForward[1196:f803] 0x4640 hello
2012-03-22 22:41:06.908 LOCMessageForward[1196:f803] 0x6a69860 hello
2012-03-22 22:41:06.908 LOCMessageForward[1196:f803] 0x4640 hello
2012-03-22 22:41:06.909 LOCMessageForward[1196:f803] 0x6a65a50 hello
2012-03-22 22:41:06.909 LOCMessageForward[1196:f803] 0x6a6b7a0 hello
2012-03-22 22:41:06.910 LOCMessageForward[1196:f803] 0x6a6aec0 hello
2012-03-22 22:41:06.910 LOCMessageForward[1196:f803] -----------------
2012-03-22 22:41:06.911 LOCMessageForward[1196:f803] 0x4640 hello
2012-03-22 22:41:06.911 LOCMessageForward[1196:f803] 0x4640 hello
2012-03-22 22:41:06.912 LOCMessageForward[1196:f803] 0x4640 hello
2012-03-22 22:41:06.912 LOCMessageForward[1196:f803] 0x6a69860 hello
2012-03-22 22:41:06.912 LOCMessageForward[1196:f803] 0x4640 hello
2012-03-22 22:41:06.913 LOCMessageForward[1196:f803] 0x6a65a50 hello
2012-03-22 22:41:06.913 LOCMessageForward[1196:f803] 0x6a6b7a0 hello
2012-03-22 22:41:06.914 LOCMessageForward[1196:f803] 0x6a6aec0 hello
2012-03-22 22:41:06.914 LOCMessageForward[1196:f803] 0x4640 hello
注意,由于“hello”为常量字符串,编译后被放在常量数据区,因此str1和str2具有相同的指针地址,但是stringWithString和stringWithFormat为啥表现不同就不明白了,不知道但是苹果那班人怎么想的?
可以肯定的是NSString和NSArray都是进行的浅拷贝,只拷贝指针,并增加指针所指实例的retainCount,并未复制该对象。