之前有过一篇文章关于iOS 属性的 iOS指示符 assign、copy、retain、strong、weak,之后看了一遍有总结了一下:
NSString 选 Strong 还是copy?
1、现分别创建NSString 的strong 和 copy 两个属性
@property(nonatomic, strong) NSString *age1;
@property(nonatomic, copy) NSString *age2;
2、创建一个NSString 常量,赋值给上面的age1和age2两个属性。
NSString *age = @"11";
NSLog(@"age: %@ - %p", age, age);
self.age1 = age;
self.age2 = age;
NSLog(@"age1: %@ - %p", self.age1, self.age1);
NSLog(@"age2: %@ - %p", self.age2, self.age2);
NSString *ageOther = [age stringByAppendingString:@"20"];
NSLog(@"age: %@ - %p", age, age);
NSLog(@"ageother: %@ - %p", ageOther, ageOther);
NSLog(@"age1: %@ - %p", self.age1, self.age1);
NSLog(@"age2: %@ - %p", self.age2, self.age2);
3、结果:
age: 11 - 0x108f28078
age1: 11 - 0x108f28078
age2: 11 - 0x108f28078
age: 11 - 0x108f28078
ageother: 1120 - 0x600000255000
age1: 11 - 0x108f28078
age2: 11 - 0x108f28078
分析:
我们可以发现,给age1和age2 赋值一个不可变的字符串的时候,都进行了浅拷贝,只拷贝了指针地址,使age、age1、age2都指向同一个地址,在对age进行增加字符串时,因为age是不可变字符串,所以age没有变化,于是age1、age2都没有变化。
总结:声明String和copy属性的String被不可变String赋值时,没有变化,都是浅拷贝,都不会发生变化。
1、现分别创建NSString 的strong 和 copy 两个属性
@property(nonatomic, strong) NSString *str1;
@property(nonatomic, copy) NSString *str2;
2、创建一个NSMutableString 可变字符串,赋值给上面的str1和str2两个属性。
NSMutableString *name = [[NSMutableString alloc] initWithString:@"Alex"];
NSLog(@"name : %@ - %p", name, name);
self.str1 = name;
self.str2 = name;
NSLog(@"str1 %@ - %p", self.str1, self.str1);
NSLog(@"str2 %@ - %p", self.str2, self.str2);
[name appendString:@"Le"];
NSLog(@"str1 %@ - %p", self.str1, self.str1);
NSLog(@"str2 %@ - %p", self.str2, self.str2);
3、结果:
name : Alex - 0x604000255cc0
str1 : Alex - 0x604000255cc0
str2 : Alex - 0xa00000078656c414
str1 : AlexLe - 0x604000255cc0
str2 : Alex - 0xa00000078656c414
分析:
我们可以看出在用可变字符串给属性变量赋值时,strong的str1 对name进行浅拷贝,只拷贝了地址,所以str1和name指向同一个地址,而copy 的 str2 对name 进行了深拷贝,str2将name复制到一个新空间内。
当我们对name增添时,此时我们可以看到和name指向相同的str1的内容改变了,而新开辟空间的str2却还保持原来的值。
总结:
声明String和copy属性的String被可变的NSMutableString name赋值时,strong类型的会随可变字符串的变化而变化,但是copy类型的却不会随可变字符串的变化而变化。所以当属性被不可变的字符串赋值时,strong和copy没有区别;当属性被可变字符串赋值时,copy不会被修改,而strong会被修改。综上所述,copy更简单、安全。
NSArray 和 NSMutableArray 是 copy 还是 strong?
1、NSMutableArray 不能被copy修饰,因为以后对数组的增删改操作在copy之后数组都会变成不可变数组,对其进行增删改都将crash。
@property (copy) NSMutableArray * a;
NSMutableArray* b = [NSMutableArray array];
a = b;
等同于
@property (strong) NSMutableArray * a;
NSMutableArray* b = [NSMutableArray array];
a = [b copy];
a在被copy之后就变成了不可变数组NSArray了。
2、NSMutableArray 被strong修饰,在赋值的时候就如上面说的那样会指向同一个地址,被定义的属性也不会改变。
@property(nonatomic, strong) NSMutableArray *arrayA;
@property(nonatomic, copy) NSMutableArray *arrayB;
NSMutableArray *arrayC = [NSMutableArray array];
NSLog(@"arrayC.class: %@ - %p", arrayC.class, arrayC);
self.arrayA = arrayC;
self.arrayB = arrayC;
NSLog(@"arrayA.class: %@ - %p", _arrayA.class, _arrayA);
NSLog(@"arrayB.class: %@ - %p", _arrayB.class, _arrayB);
[self.arrayA removeAllObjects];
[self.arrayB removeAllObjects];
结果:
arrayC.class: __NSArrayM - 0x604000251220
arrayA.class: __NSArrayM - 0x604000251220
arrayB.class: __NSArray0 - 0x6000000021a0
-[__NSArray0 removeAllObjects]: unrecognized selector sent to instance 0x6000000021a0
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSArray0 removeAllObjects]: unrecognized selector sent to instance 0x6000000021a0'
分析:我们可以看到arrayA 和 arrayC的指向同一个地址,且类型都是mutable的,arrayB的类型发生了改变变成不可变的类型。所以,NSMutableArray被copy修饰之后就变成不可变的,在对其操作时容易crash。
而NSArray被copy或者strong修饰的时候和NSString相同。
1、当arrayA被strong修饰,且被可变数组赋值,可变数组arrayMB改变,被strong修饰属性arrayA也做同样修改,arrayA和arrayMB指向的地址相同;
2、当array被copy修饰,且被可变数组赋值,可变数组arrayMB改变,被copy修饰的属性arrayB没有被修改,因为arrayB深拷贝arrayMB,arrayB和arrayMB在两个内存块中。
3、不管array被strong、copy修饰,只要被不可变数组赋值,此时都指向同一个内存地址。