1.什么时候使用copy。
copy修饰的是不可变的对象。即使后边声明的是NSMutableXXX ,它实际上的真实数据类型也是不可变的。这时候对其进行操作就会崩溃了。
copy用作浅拷贝,只拷贝对象的指针,对象的内存是不变的。只是新开辟了一块指针类型的内存空间,这个内存空间里的内容是指向这个对象的指针。
通常情况下,当我们定义属性的时候,我们想要的是一个不可变的对象的时候。比如NSString,NSArray。
当我们给这个不可变的对象赋值的时候,要分两种情况考虑。
@property (nonatomic, copy) NSString *copyedString;
@property (nonatomic, strong) NSString * strongString;
①所赋的值对象也是不可变的。
NSString *string = @"123asd";
self.copyedString = string;
self.strongString = string;
NSLog(@"stringP = %p ",string);
NSLog(@"self.copyedStringP = %p self.copyedString class = %@", self.copyedString, [self.copyedString class]);
NSLog(@"self.strongStringP = %p self.strongString class = %@", self.strongString, [self.strongString class]);
运行结果:
stringP = 0x10e4f9078
self.copyedStringP = 0x10e4f9078 self.copyedString class = __NSCFConstantString
self.strongStringP = 0x10e4f9078 self.strongString class = __NSCFConstantString
②所赋的值对象是可变的。
NSString *string = @"123asd".mutableCopy;
self.copyedString = string;
self.strongString = string;
NSLog(@"stringP = %p ",string);
NSLog(@"self.copyedStringP = %p self.copyedString class = %@", self.copyedString, [self.copyedString class]);
NSLog(@"self.strongStringP = %p self.strongString class = %@", self.strongString, [self.strongString class]);
运行结果:
stringP = 0x600001e9b4e0
self.copyedStringP = 0xc862b1052a14edfe self.copyedString class = NSTaggedPointerString
self.strongStringP = 0x600001e9b4e0 self.strongString class = __NSCFString
当是第一种情况的时候其实strong和copy是没有区别的,_str的指针地址都一样,二者都是对string的引用计数加了1.
但是第二种情况的时候用strong修饰,和第一种情况仍然一样,引用计数加1,但此时虽然声明是NSString,但是strongString是对string这个可变字符串变量的一次持有,实际上strongString指向的就是这个可变的字符串,所以现在的strongString并不是不可变的字符串了。而copyedString不一样,copy时string的内存空间是可变的,与copyedString声明的所有权修饰符copy并不符合,所以此时需要做深拷贝,拷贝了内容,放在一块新的内存不可变的地址中去。
2.一种错误的使用情况
当 copy 修饰可变类型集合(例如:NSMutableArray)时,赋值后,会导致可变类型属性变为不可变类型,然后在调用可变类型方法时,会产生异常错误。
产生异常的原因是 copy 属性在运行时赋值时调用了 -copyWithZone:赋值,将可变类型转换为不可变类型。
3.一道题
所以表面上self.array是NSArray对象, 其实骨子里是NSMutableArray对象.这样的话将会对后期DEBUG增加很大的成本, 可能会导致莫名其妙的错误.
网友评论