关于oc中的 @property中的retain和Copy的运用,虽然描述可能有些冗长但相信坚持看完你一定能有所收获
首先先看一下OC中的关于* &之间的关系
NSString * str=@"123";
NSLog(@"%@",str);
NSLog(@"%@",*&str);
NSLog(@"%p",str);
NSLog(@"%p",&str);
2015-09-15 13:07:31.772 test123[1359:52116] 123
2015-09-15 13:07:31.773 test123[1359:52116] 123
2015-09-15 13:07:31.773 test123[1359:52116] 0x100001038
2015-09-15 13:07:31.773 test123[1359:52116] 0x7fff5fbff728
copy分为浅拷贝和深copy
copy方式又分为copy和mutableCopy两种
要实现Copy或者mutableCopy就要遵守
-(id)mutableCopyWithZone:(NSZone *)zone
-(id)copyWithZone:(NSZone *)zone
不然是不能实现Copy的系统给出的已经实现了的有
NSString ,NSArray,NSData;NSDictionary
至于NSNumber因为其本身不可变所以可以执行Copy但不能mutableCopy
其它的类要想使用Copy都要遵循协议并实现方法
-(id)copyWithZone:(NSZone *)zone
{
Dog *dog=[[[[Dog class]allocWithZone:zone]init]autoRelease];
dog.name=self.name;
dog.age=self.age;
return dog;
}
NSString *str=@"123";
NSString *s1=[strcopy];
NSString * s2=[strmutableCopy];
NSMutableString * s3=[strcopy];
NSMutableString * s4=[strmutableCopy];
NSMutableString * s5=[s4copy];
NSMutableString * s6=[s4mutableCopy];
NSString * s7 =[s4copy];
NSString * s8=[s4mutableCopy];
NSLog(@"str:%@ ,%p, %p",str,str,&str);
NSLog(@"s1: %@ ,%p, %p",s1,s1,&s1);
NSLog(@"s2: %@ ,%p, %p",s2,s2,&s2);
NSLog(@"s3: %@ ,%p, %p",s3,s3,&s3);
NSLog(@"s4: %@ ,%p, %p",s4,s4,&s4);
NSLog(@"s5: %@ ,%p, %p",s5,s5,&s5);
NSLog(@"s6: %@ ,%p, %p",s6,s6,&s6);
NSLog(@"s7: %@ ,%p, %p",s7,s7,&s7);
NSLog(@"s8: %@ ,%p, %p",s8,s8,&s8);
2015-09-15 13:33:17.736 test111[1434:61053] str :123 ,0x1058c07f0, 0x7fff5a344c30
2015-09-15 13:33:17.737 test111[1434:61053] s1 : 123 ,0x1058c07f0, 0x7fff5a344c28
2015-09-15 13:33:17.737 test111[1434:61053] s2 : 123 ,0x7fe9405435a0, 0x7fff5a344c20
2015-09-15 13:33:17.737 test111[1434:61053] s3 : 123 ,0x1058c07f0, 0x7fff5a344c18
2015-09-15 13:33:17.738 test111[1434:61053] s4 : 123 ,0x7fe940537c00, 0x7fff5a344c10
2015-09-15 13:33:17.738 test111[1434:61053] s5 : 123 ,0x7fe940542820, 0x7fff5a344c08
2015-09-15 13:33:17.738 test111[1434:61053] s6 : 123 ,0x7fe9405451a0, 0x7fff5a344c00
2015-09-15 13:33:17.738 test111[1434:61053] s7 : 123 ,0x7fe940537c40, 0x7fff5a344bf8
2015-09-15 13:33:17.738 test111[1434:61053] s8 : 123 ,0x7fe940545ab0, 0x7fff5a344bf0
1. 凡是mutableCopy的都是内容
2. 源对象是可变的话Copy/和mutableCopy的都是内容;
3. 源对象是不变的话Copy的都是地址也就是指针
4. 例如s3 如果源对象是不可变的那么将源对象copy后是可以用一个可变的字符串进行接收的,如果不改变接收对象的值的话是没有问题的但是如果将接收对象进行增删改的话就会程序就会崩溃
reason: 'Attempt to mutate immutable object with appendFormat
因为你尝试将一个不可变的对象进行可变操作
@property(retain)NSString *rStr;
@property(copy)NSString *cStr;
//源对象是不可变的
NSString *str=@"123";
self.rStr=str;
self.cStr=str;
NSLog(@"str:%p,%p",str,&str);
NSLog(@"rStr:%p %p",self.rStr,&_rStr);
NSLog(@"cStr:%p %p",self.cStr,&_cStr);
2015-09-15 13:45:00.083 test111[1467:64776] str: 0x105b767f0,0x7fff5a08ec38
2015-09-15 13:45:00.083 test111[1467:64776] rStr:0x105b767f0 0x7fdbc0455138
2015-09-15 13:45:00.084 test111[1467:64776] cStr:0x105b767f0 0x7fdbc0455140
retain只是将源对象 的计数器加一 所以rStr的str%p的结果是相同的因为它们指向的是相同的对象
可以看到 因为源对象是不可变的所以只需要copy其地址就可以了不需要重新开辟地址占用资源 所以Copy的都是地址也就是通常所谓的指针拷贝
到这里再看一个例子
NSString * s=@"test";
NSLog(@"%ld",s.retainCount);
[s retain ]; NSLog(@"%ld",s.retainCount);
[s release];
NSLog(@"%ld",s.retainCount);
2015-09-16 19:11:12.234 test[4544:2056420] -1
2015-09-16 19:11:12.235 test[4544:2056420] -1
2015-09-16 19:11:12.235 test[4544:2056420] -1
因为 @"test"是以个OC的字符串常量,不管对test执行多少次retain和release系统堆不会报错其引用计数为-1 或者是一个非常大的值 系统是不会去释放一个常量的;
NSString *str0=[NSString stringWithFormat:@"test%d",2];
NSLog(@"%ld",str0.retainCount);
NSString *str = [NSString stringWithString:[NSString stringWithFormat:@"test%d",2]];
NSLog(@"%ld",str.retainCount);
NSString * str3=
NSLog(@"%ld",str3.retainCount);
2015-09-16 19:23:31.418 test[4627:2061789] 1
2015-09-16 19:23:31.418 test[4627:2061789] 2
2015-09-16 19:23:31.418 test[4627:2061789] 3
可以看到 通过 [ NSString stringWithFormat : @"test%d" , 2 ]; [NSString stringWithString:[NSString stringWithFormat:@"test%d",2]]; [NSString stringWithString:str];
但是当使用[NSString stringWithString:@"test"]这样方式创建str的时候系统会警告 Using 'stringWithString' with a literal is redundant 告诉我们使用不必要的创建方式
NSString * str4=str3;
NSLog(@"%ld",str4.retainCount);
2015-09-16 19:23:31.418 test[4627:2061789] 3
可以看到用=赋值语句不会增加引用计数只是简单的赋值 assign
NSString * str5=[str4 retain];
NSLog(@"%ld",str5.retainCount);
2015-09-16 19:23:31.419 test[4627:2061789] 4
NSString * str6=[str5 copy];
NSLog(@"%ld",str6.retainCount);
2015-09-16 19:23:31.419 test[4627:2061789] 5
结合上面的retain和Copy的区别共同点可以看到 retain和Copy都会将引用计数加一以上可以直接将引用计数加一的原因就是源对象和目标对象都是不可变的 所以这时候只需要将内容的引用计数加一就好不需要从新开辟内存 节省内存资源
NSMutableString * str7=[str6 mutableCopy];
NSLog(@"%ld",str7.retainCount);
2015-09-16 19:23:31.419 test[4627:2061789] 1
看完str在看Array
NSArray * arr=@[@"1",@"2"];
NSLog(@"%ld",arr.retainCount);
NSArray * arr1=[arr copy];
NSLog(@"%ld",arr1.retainCount);
NSLog(@"%ld",arr.retainCount);
NSMutableArray * arr2=[arr1 copy];
NSLog(@"%ld",arr2.retainCount);
NSMutableArray * arr3=[arr2 mutableCopy];
NSLog(@"%ld",arr3.retainCount);
2015-09-16 19:23:31.419 test[4627:2061789] 1
2015-09-16 19:23:31.419 test[4627:2061789] 2
2015-09-16 19:23:31.419 test[4627:2061789] 2
2015-09-16 19:23:31.419 test[4627:2061789] 3
2015-09-16 19:23:31.419 test[4627:2061789] 1
结果和str也是相同的
//源对象是可变的
NSMutableString *mStr=[NSMutableStringstringWithFormat:@"abc"];
self.rStr=mStr;
self.cStr=mStr;
NSLog(@"mStr:%p,%p",mStr,&mStr);
NSLog(@"rStr:%p %p",self.rStr,&_rStr);
NSLog(@"cStr:%p %p",self.cStr,&_cStr);
2015-09-15 13:45:00.084 test111[1467:64776] mStr:0x7fdbc0524410,0x7fff5a08ec30
2015-09-15 13:45:00.084 test111[1467:64776] rStr:0x7fdbc0524410 0x7fdbc0455138
2015-09-15 13:45:00.084 test111[1467:64776] cStr:0x7fdbc0524b10 0x7fdbc0455
对于可变的 因为 retain只是将计数加1所以 rStr 和 mStr用%p打印的结果还是相同的,因为它们指向的仍然是相同的对象而 Copy的结果是不同的因为 源对象是可变的Copy完的结果也会进行增删改所以如果Copy指针的话那么源对象改变的时候或者目标对象改变的时候两者都会改变,当源对象/目标对象被释放的时候,目标对象或者源对象也会被释放的。而我们一般都不希望 在Copy完了以后两者还联系 一个被释放了另一个也被释放,所以会从新开辟一段新地址
其中的内容是和源内容是相同的。
@property(retain)NSString *name;
-(void)setName:(NSString *)name{
if (self.name !=name) {
[self.namerelease];
[[self.name = name]retain];
}
}
@property(copy)NSString *name;
-(void)setName:(NSString *)name{
if (self.name !=name) {
[self.namerelease];
[[self.name = name]copy];
}
}