对象的copy&mutableCopy

copy  目的是为了创建新的对象副本,在objc中有如下区别:
不可变对象 copy  == 对象retain    (这是由于ios内存优化的原因,因为不可变对象copy创建新对象其实还是和源对象是一样的,那么分配内存的时候直接不分配了而是指向源对象retain count就+1了,所以相当于retain)

可变对象 copy      == 创建了一个新的不可变的对象

可变/不可变对象 mutablecopy == 创建一个新的可变对象

有位前辈这么总结的,我觉得很好:
copy,生成的是不可变对象,无论源对象是否是可变的
mutablecopy,新对象是可变的,无论源对象是否可变

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


 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值