在iOS中属性的retain与copy的区别
- retain:对象引用计数+1,本质上是指针的拷贝
-
- copy:拷贝出一个新的对象,本质上是对象(地址)的拷贝
- 例子:创建一个类
-
<span style="font-size:14px;">@interface Compare : NSObject { //为Compare类添加两个属性 NSString *_retainString; NSString *_copyString; } //我们分别将两个属性设置成不同的特性,一个为retain, 一个为copy,这样为了做个对照。 @property(nonatomic,retain)NSString *retainString; @property(nonatomic,retain)NSString *copyString;</span>
<span style="font-size:14px;">//生成的设置方法(赋值方法)如下 - (void)setRetainString:(NSString *)retainString { //保留一份传入参数,这时候retainString引用计数加1 [retainString retain]; //避免造成内存泄露(如果省略这个代码,我们对该变量赋值两次,那么我们第二次赋值后,它持有第一次传入的对象并且没有释放,将一直存在,造成内存泄露),所以先对实例变量进行释放,然后再做新的引用 [_retainString release]; //这时候 _retainString 与 retainString 指向的时同一个对象(同一个地址),故而参数possessionName改变的时候,实例变量也会改变 _retainString = retainString; } - (void)setCopyString:(NSString *)copyString { //避免造成内存泄露(如果省略这个代码,我们对该变量赋值两次,那么我们第二次赋值后,它持有第一次传入的对象并且没有释放,将一直存在,造成内存泄露),所以先对实例变量进行释放,然后再做新的引用 [_copyString release]; //这时候 _copyString 和 copyString 指向的是不同的地址(也就是不同的对象),所以即使对入参进行改变,也不会引起实例变量的改变。 _copyString = [copyString copy]; }</span>
接下来我们进行测试 -
<span style="font-size:14px;"><span style="white-space:pre"> </span>//生成一个实例 Compare *compare = [[Compare alloc] init]; NSMutableString *string = [NSMutableString stringWithString:@"string"]; //第一次给compare里面的两个属性赋值 [compare setRetainString:string]; [compare setCopyString:string]; //第一次打印compare里面的两个属性的值 NSLog(@"retainString = %@", compare.retainString); NSLog(@"copyString = %@", compare.copyString); //更改传入参数的值 [string appendFormat:@"+append"]; //传入参数变成string+append //第二次打印compare里面的两个属性的值 NSLog(@"retainString = %@", compare.retainString); NSLog(@"copyString = %@", compare.copyString);</span>
结果如下:
-
第一次打印结果:
-
retainString = string
copyString = string
第二次打印结果: -
retainString = string+append
-
copyString = string
这样两次打印的结果会让你明白copy和retain两个特性的明显区别
很明显:被加以retain特性的类属性,在外界参数改变的情况下它也随之改变,说明是共用了一块内存;
而加以copy特性的类属性,在外界参数改变的情况下它并没有随之改变,说明它只是copy了一份一模一样的内存内容。
得出的结论是:
如果属性的类型是可修改的子类(即该类的实例是可修改的),那么通常情况下,该属性应该有copy特性,而不是retain特性。
这样,类实例就可以拥有一份相应对象的完全独立的备份。