參考:
[1]參考庫:記憶體管理編程指南
將一個指標p1直接賦值給另外一個指標p2,即:p2=p1,其實p1,p2指向的同一個執行個體對象,任何對p1進行的操作都會影響p2,因為他們指向同個地址的執行個體對象。具體的就不說了,所以如果需要拷貝一個對象,而不只是指標賦值,在C++中有“拷貝建構函式”來實現此功能。objetive-c則通過copy和mutableCopy方法來實現。
首先,objetive-c中有NSCopying 和NSMutableCopying 兩種協議,分別聲明了copyWithZone和mutableCopyWithZone方法。協議:就是把若干類中具有相同功能的方法都抽象出來,定義在一起。因此任何需要copy操作的類,只需要遵從NSCopying 和NSMutableCopying協議,並實現copyWithZone和mutableCopyWithZone方法,實現對象的拷貝。
其次,方法copy產生不可修改的對象,方法mutableCopy產生可修改的對象。產生是否可修改的對象跟之前拷貝的對象是否可修改沒有關係,跟調用copy還是mutablecopy有關係。
測試代碼如下,首先LOCBird為包含NSCopying 或NSMutableCopying 協議,如下所示。
@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的拷貝方法
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,並未複製該對象。