美文网首页
关于strong、copy误区

关于strong、copy误区

作者: 我是C | 来源:发表于2017-02-07 16:55 被阅读97次

说一说比较基础的东西,老生常谈的strong、copy.
一.

#import "ViewController.h"

@interface ViewController ()
@property (nonatomic,strong)NSString *str;
@property (nonatomic,copy)NSString *strC;
@end
@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    NSString *mStr =@"adc";
    self.str = mStr;
    self.strC = mStr;
    mStr = @"de";

    NSLog(@"%p--%p--%p",self.str,self.strC,mStr);
    NSLog(@"%@--%@--%@",self.str,self.strC,mStr);
}
@end

猜一猜结果........

0x100ddc078--0x100ddc078--0x100ddc098
adc--adc--de

有的人会问不是strong吗,应该输出de,接下来再看看

#import "ViewController.h"

@interface ViewController ()
@property (nonatomic,strong)NSString *str;
@property (nonatomic,copy)NSString *strC;
@end
@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    NSMutableString *mStr = [NSMutableString stringWithFormat:@"abc"];
    self.str = mStr;
    self.strC = mStr;
    [mStr appendString:@"de"];

    NSLog(@"%p--%p--%p",self.str,self.strC,mStr);
    NSLog(@"%@--%@--%@",self.str,self.strC,mStr);
}
@end

再来猜猜结果

0x6000002606c0--0xa000000006362613--0x6000002606c0
abcde--abc--abcde

这次strong 对了啊


strong: 实际是retain 持有对象
copy:浅拷贝等同strong ,深拷贝是复制对象和指针

第一个:因为mStr发生了指针指向变化, mStr指向了新的内存,而strong copy的字符串还是指向最初的内存,所以strong输出的还是adc.地址一样是因为

1

第二个:将mStr赋值给NSString,然后再mStr追加字符,但是追加字符地址是没变的,所以strong的字符串还是和mStr指向同一块地址,而copy的字符串是指向一块新的内存,就是深拷贝,结果如图.


二.
关于对象拷贝,首先需要实现<NSCopying>

@interface Person : NSObject<NSCopying>
@property (nonatomic,copy)NSString *strC;
@property (nonatomic,strong)NSString *str;
@end

@implementation Person

- (id)copyWithZone:(nullable NSZone *)zone{
    Person *p = [Person allocWithZone:zone];
    p.str = self.str;
    p.strC = self.strC;
    return p;
}
@end


@interface ViewController ()
@property (nonatomic,strong)Person *per;

@end
@interface ViewController ()
@property (nonatomic,strong)Person *per;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    Person *p = [Person new];
    p.str = @"111";
    p.strC = @"222";
    self.per = p;
    NSLog(@"str 地址:%p--%p",p.str,self.per.str);
    NSLog(@"str 值:%@--%@",p.str,self.per.str);
    
    NSLog(@"strC 地址:%p--%p",p.strC,self.per.strC);
    NSLog(@"strC 值:%@--%@",p.strC,self.per.strC);


    p.str = @"333";
    p.strC = @"444";
    NSLog(@"str 地址:%p--%p",p.str,self.per.str);
    NSLog(@"str 值:%@--%@",p.str,self.per.str);
    
    NSLog(@"strC 地址:%p--%p",p.strC,self.per.strC);
    NSLog(@"strC 值:%@--%@",p.strC,self.per.strC);

}

先声明@property (nonatomic,strong)Person *per;首先不会走copyWithZone方法,打印结果

str 地址:0x10ee99078--0x10ee99078
str 值:111--111
strC 地址:0x10ee99098--0x10ee99098
strC 值:222--222
str 地址:0x10ee99138--0x10ee99138
str 值:333--333
strC 地址:0x10ee99158--0x10ee99158
strC 值:444--444

会发现对于Person类的str声明无论是copy还是strong,打印结果一致,都是浅拷贝=strong,上一个问题的推论正确.
**有一点需要注意:p.str再次赋新值,self.per.str也跟着变了,为什么?

我们来验证一下:

先重写Person类的str属性setter方法:

- (void)setStr:(NSString *)str{
    NSLog(@"赋值前:%p--------%p",_str,str);
    NSLog(@"赋值前指针地址:%p--------%p",&_str,&str);

    _str = str;
    NSLog(@"赋值后:%p--------%p",_str,str);
    NSLog(@"赋值后指针地址:%p--------%p",&_str,&str);

}
Person *p = [Person new];
    p.str = @"111";
    self.per = p;

    p.str = @"333";

结果

赋值前:0x0--------0x108c070f8
赋值前指针地址:0x6000002210d0--------0x7fff56ff8a38
赋值后:0x108c070f8--------0x108c070f8
赋值后指针地址:0x6000002210d0--------0x7fff56ff8a38
赋值前:0x108c070f8--------0x108c07138
赋值前指针地址:0x6000002210d0--------0x7fff56ff8a38
赋值后:0x108c07138--------0x108c07138
赋值后指针地址:0x6000002210d0--------0x7fff56ff8a38

首先区分一下概念,指针地址和指针指向的地址,指针变量其实有两个内容.
指针本身的地址,即指针地址;
指针指向的地址,即对象地址;
我们一般所谓的操作指针,都是指操作对象,所以我们会用变量来代替对象进行一些操作.以上概念不要搞混淆了,接下来.

在属性初始化以后,两次赋值的均调用setter方法,实际赋值是赋值到_str 这个变量上,然后打印了_str指针地址,发现指针地址初始化以后一直是一个,也就是0x6000002210d0.指针指向的地址在赋值后,是发生变化的,那么我们也就解释清楚:

*对于对象属性而言,每次我们赋值的时候,属性指针本身的地址,在初始化以后一直是一个,赋值只是让指向的地址发生变化,所以每次p.str重新赋值,会让self.per.str,也发生改变;

然后我们声明@property (nonatomic,copy)Person *per;首先会走copyWithZone方法,打印结果

str 地址:0x10e9fa078--0x10e9fa078
str 值:111--111
strC 地址:0x10e9fa098--0x10e9fa098
strC 值:222--222
str 地址:0x10e9fa138--0x10e9fa078
str 值:333--111
strC 地址:0x10e9fa158--0x10e9fa098
strC 值:444--222

发现只要Person对象发生copy,对象里的属性也会随着一起变化


总结:
1.copy是为了安全,防止NSMutableString赋值给NSString,防止改变最初的字符串的值.
2.在NS*情况下,copy和strong作用是一样的.
3.copy strong 发生在set方法的时候
4.自定义对象需要实现NSCopying协议,只要对象发生copy,对象里的属性也会随着一起变化,对象属性的变化是随着对象的变化而变化.
5.属性操作,我们都是用的setter getter方法,对于已经确定的对象,对象里的属性,在第一次赋值的时候,会确定属性本身的地址,每次赋值,只是指针指向的地址变了


如果有错,忘指出,我会改正.

相关文章

网友评论

      本文标题:关于strong、copy误区

      本文链接:https://www.haomeiwen.com/subject/cuipittx.html