本文仅针对使用字符串、数组、字典时,对copy和Strong展开讨论
1.不可变字符串
申明copy和strong属性字符串
@property (strong, nonatomic) NSString *strStrong;
@property (copy, nonatomic) NSString *strCopy;
// 不可变字符串
NSLog(@"不可变字符串:");
NSString *str = @"aaaa";
NSLog(@"str = %@ 内存地址 = %p 指针地址 = %p",str,str,&str);
self.strStrong = str;
NSLog(@"strong = %@ 内存地址 = %p 指针地址 = %p",self.strStrong,self.strStrong,&_strStrong);
self.strCopy = str;
NSLog(@"copy = %@ 内存地址 = %p 指针地址 = %p\n",self.strCopy,self.strCopy,&_strCopy);
打印结果
不可变字符串:
str = aaaa 内存地址 = 0x104ec4098 指针地址 = 0x7ffeead3bbd8
strong = aaaa 内存地址 = 0x104ec4098 指针地址 = 0x7fe70100e600
copy = aaaa 内存地址 = 0x104ec4098 指针地址 = 0x7fe70100e608
对不可变字符串进行操作:
str = @"bbb";
NSLog(@"对不可变字符串操作后:");
NSLog(@"str = %@ 内存地址 = %p 指针地址 = %p",str,str,&str);
NSLog(@"strong = %@ 内存地址 = %p 指针地址 = %p",self.strStrong,self.strStrong,&_strStrong);
NSLog(@"copy = %@ 内存地址 = %p 指针地址 = %p\n",self.strCopy,self.strCopy,&_strCopy);
打印结果
对不可变字符串操作后:
str = bbb 内存地址 = 0x104ec4118 指针地址 = 0x7ffeead3bbd8
strong = aaaa 内存地址 = 0x104ec4098 指针地址 = 0x7fe70100e600
copy = aaaa 内存地址 = 0x104ec4098 指针地址 = 0x7fe70100e608
结论:源对象为不可变字符串而言,不论使用copy还是strong属性,所对应的值是不发生变化,strong和copy并没有开辟新的内存,即并不是深拷贝。此时,使用copy或是strong,并没有对数据产生影响。
2.可变字符串
// 可变字符串
NSLog(@"可变字符串:");
NSMutableString *mutableStr = [[NSMutableString alloc] initWithString:@"kobe"];
NSLog(@"mutableStr = %@ 内存地址 = %p 指针地址 = %p",mutableStr,mutableStr,&mutableStr);
self.strStrong = mutableStr;
NSLog(@"strong = %@ 内存地址 = %p 指针地址 = %p",self.strStrong,self.strStrong,&_strStrong);
self.strCopy = mutableStr;
NSLog(@"copy = %@ 内存地址 = %p 指针地址 = %p\n",self.strCopy,self.strCopy,&_strCopy);
打印结果
可变字符串:
mutableStr = kobe 内存地址 = 0x60000005b150 指针地址 = 0x7ffeead3bbd0
strong = kobe 内存地址 = 0x60000005b150 指针地址 = 0x7fe70100e600
copy = kobe 内存地址 = 0xa00000065626f6b4 指针地址 = 0x7fe70100e608
对可变字符串进行操作:
NSLog(@"对可变字符串操作后:");
[mutableStr appendString:@"-bryant"];
NSLog(@"mutableStr = %@ 内存地址 = %p 指针地址 = %p",mutableStr,mutableStr,&mutableStr);
NSLog(@"strong = %@ 内存地址 = %p 指针地址 = %p",self.strStrong,self.strStrong,&_strStrong);
NSLog(@"copy = %@ 内存地址 = %p 指针地址 = %p",self.strCopy,self.strCopy,&_strCopy);
打印结果
对可变字符串操作后:
mutableStr = kobe-bryant 内存地址 = 0x60000005b150 指针地址 = 0x7ffeead3bbd0
strong = kobe-bryant 内存地址 = 0x60000005b150 指针地址 = 0x7fe70100e600
copy = kobe 内存地址 = 0xa00000065626f6b4 指针地址 = 0x7fe70100e608
结论:数据源为可变字符串而言,使用copy申明属性,会开辟一块新的内存空间存放值,源数据不论怎么变化,都不会影响copy属性中的值,属于深拷贝;使用strong申明属性,不会开辟新的内存空间,只会引用到源数据内存地址,因此源数据改变,则strong属性也会改变,属于浅拷贝。
在实际开发中,我们不希望源数据改变影响到属性中的值,故而使用copy来申明。
3.属性为可变数组、可变字典
例如:当我们使用copy修饰NSMutableArray时
@property (copy, nonatomic) NSMutableArray *originArray;
self.originArray = [NSMutableArray arrayWithCapacity:0];
NSLog(@"self. originArray class name %@",[self.originArray class]);
打印结果:self. originArray class name __NSArrayI
我们可以看到,copy申明的可变数据,初始化或复值之后,变成不可变数组,对数组执行增,删会跑出错误。这是因为copy属性修饰后,在初始化或赋值时,会先执行copy操作,然后赋值。