对象的copy&mutableCopy

参考:

[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,并未复制该对象。




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值