iOS 属性之 strong和copy修饰的区别
//1.当生成一个不可变字符串,通过下划线进行赋值。
NSString *textString =[NSString stringWithFormat:@"初始化字符串"];
_strongtitle=textString;
_ccopytitle=textString;
NSLog(@"//1.当生成一个不可变字符串,通过下划线进行赋值。");
NSLog(@"textString: %p , %p , %@", textString, &textString, textString);
NSLog(@"_strongtitle: %p , %p , %@", _strongtitle, &_strongtitle, _strongtitle);
NSLog(@" _ccopytitle: %p , %p , %@", _ccopytitle, &_ccopytitle, _ccopytitle);
//2.当生成一个不可变字符串,通过点语法赋值。
NSString *textString1 =[NSString stringWithFormat:@"初始化字符串"];
self.strongtitleP=textString1;
self.ccopytitleP=textString1;
NSLog(@" //2.当生成一个不可变字符串,通过点语法赋值。");
NSLog(@"textString1: %p , %p , %@", textString1, &textString1, textString1);
NSLog(@"self.strongtitleP: %p , %p , %@", _strongtitleP, &_strongtitleP, _strongtitleP);
NSLog(@"self.ccopytitleP: %p , %p , %@", _ccopytitleP, &_ccopytitleP, _ccopytitleP);
//3.当生成一个可变字符串,通过下划线进行赋值。
NSMutableString *mutabTextString =[NSMutableString stringWithFormat:@"初始化可变字符串"];
_strongtitlePotent=mutabTextString;
_ccopytitlePotent=mutabTextString;
[mutabTextString setString:@"修改后字符串"];
NSLog(@" //3.当生成一个可变字符串,通过下划线进行赋值。");
NSLog(@"mutabTextString: %p , %p , %@", mutabTextString, &mutabTextString, mutabTextString);
NSLog(@"_strongtitlePotent: %p , %p , %@", _strongtitlePotent, &_strongtitlePotent, _strongtitlePotent);
NSLog(@" _ccopytitlePotent: %p , %p , %@", _ccopytitlePotent, &_ccopytitlePotent, _ccopytitlePotent);
//4.当生成一个可变字符串,通过点语法赋值。
NSMutableString *mutabTextString1 =[NSMutableString stringWithFormat:@"初始化可变字符串"];
self.strongtitleSet=mutabTextString1;
self.ccopytitleSet=mutabTextString1;
[mutabTextString1 setString:@"修改后字符串"];
NSLog(@"//4.当生成一个可变字符串,通过点语法赋值。");
NSLog(@"mutabTextString: %p , %p , %@", mutabTextString1, &mutabTextString1, mutabTextString1);
NSLog(@"self.strongtitleSet: %p , %p , %@", _strongtitleSet, &_strongtitleSet, _strongtitleSet);
NSLog(@"self.ccopytitleSet: %p , %p , %@", _ccopytitleSet, &_ccopytitleSet, _ccopytitleSet);
//1.当生成一个不可变字符串,通过下划线进行赋值。
textString: 0x282f33330 , 0x16ef11b58 , 初始化字符串
_strongtitle: 0x282f33330 , 0x1017069b0 , 初始化字符串
_ccopytitle: 0x282f33330 , 0x1017069b8 , 初始化字符串
//2.当生成一个不可变字符串,通过点语法赋值。
textString1: 0x282f32d90 , 0x16ef11b50 , 初始化字符串
self.strongtitleP: 0x282f32d90 , 0x1017069c0 , 初始化字符串
self.ccopytitleP: 0x282f32d90 , 0x1017069c8 , 初始化字符串
//3.当生成一个可变字符串,通过下划线进行赋值。
mutabTextString: 0x282f33360 , 0x16ef11b48 , 修改后字符串
_strongtitlePotent: 0x282f33360 , 0x1017069d0 , 修改后字符串
_ccopytitlePotent: 0x282f33360 , 0x1017069d8 , 修改后字符串
//4.当生成一个可变字符串,通过点语法赋值。
mutabTextString: 0x282f1ccf0 , 0x16ef11b40 , 修改后字符串
self.strongtitleSet: 0x282f1ccf0 , 0x1017069e0 , 修改后字符串
self.ccopytitleSet: 0x282f1cab0 , 0x1017069e8 , 初始化可变字符串
通过打印对应的对象地址,指针地址,对象地址存储的值可以得出以下结论:
一,当变量为不可变字符串时,无论通过点语法赋值还是通过下划线赋值,当前属性指向的内存不变,使用strong或copy无区别。
二.当变量为一个可变字符串:分两种情况
1)当通过下划线赋值时,属性指向的内存空间不变,并且当可变字符串内容发生更改时,被赋值的属性也会发生变化。
2)当通过点语法进行赋值时,strong 修饰的属性指向的内存地址并没有发生改变,只是引用计数加一,当可变字符串内容发生更改时,strong修饰的属性值也会发生更改。但是copy 修饰的属性 指向的内存地址会发生更改,并且当我们对可变字符串进行更改时,copy修饰的属性值并不会发生改变,进而说明copy修饰的属性在底层实现时会重新copy一份内存,并指向这块内存,即深拷贝。
3)下划线属性赋值和通过点语法进行属性赋值有很大差距,这就要说起成员变量和属性的差异,属性在低层的实现,是生成一个带下划线的成员变量,同时生成get和set方法。当我们通过下划线对属性赋值时其实是对成员变量进行赋值,而当你对底层有足够多的了解时,其实copy修饰的属性在底层的实现是通过,set_propety 方法访问内存,而非copy修饰的属性,会通过内存偏移的方式访问内存。所以当使用点语法赋值时会自动调用系统的set方法。set方法的底层实现可以参考:iOS底层原理之类,元类数据结构探索