说一说比较基础的东西,老生常谈的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.地址一样是因为
第二个:将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方法,对于已经确定的对象,对象里的属性,在第一次赋值的时候,会确定属性本身的地址,每次赋值,只是指针指向的地址变了
如果有错,忘指出,我会改正.