为什么NS* 要使用copy修饰?
为什么NSMutable*要用strong修饰?
First, 我们得看下copy和strong有什么区别,它们都是属性的修饰符,关键在于它们对应了不同的setter方法实现
strong :
-(T)setA:(T)a {
if (_a != nil) {
[_a release];
}
[a retain];
_a = a;
return _a;
}
copy:
-(T)setA:(T)a {
if (_a != nil) {
[_a release];
}
_a = [a copy]; // 如果a是可变类型,则返回一个不可变副本,
// 如果a是不可变类型,则返回其本身
return _a;
}
这里插播一段小知识:下划线使用属性和self.使用属性有啥区别
使用下划线对属性赋值时,是直接对属性赋值,如
@property (nonatomic, strong) T *a;
T *b = [[T alloc] init];
_a = b;
这里 b 的引用计数不会加一,_a 直接指向了b指向的地址,引用计数仍为一,如果使用MRC的情况下,
[b release];
这时再进行
[_a release];
则会崩溃,原因就在于引用计数原先没有增加,
[b release];
后引用计数已经为0了。当引用计数为0时,系统就会调用delloc释放该对象和该对象所拥有的实例,该对象就销毁了。
而使用self.对属性赋值时则不同,它实际是调用了属性的setter方法
欢迎回来,strong修饰的属性赋值时指向的是同一块地址,引用计数加一,属于浅拷贝,而使用copy修饰的属性在赋值时将获得右值的一份不可变的副本
For example,如果使用strong修饰一个NSString *属性aStr
@property (nonatomic, strong) NSString *aStr;
NSMutableString *mStr = [[NSMutableString alloc] init];
self.aStr = mStr; //这里mStr引用计数为2
_aStr = mStr; //这里mStr引用计数仍为2
使用NSString *是说明定义的属性在初始化后其内容不应该再改变了,NSMutableString *是说明定义的属性内容可以改变,而这时如果将mStr赋值给aStr,因为使用的是strong修饰符,那么aStr将指向mStr的地址,mStr改变值的时候aStr的值也改变了,将与原意相悖;而使用copy修饰就不会有这情况产生了。
而如果将一个可变属性用copy修饰,则可能会造成灾难性结果(请先再回看下上文中copy对应的setter方法):
@property (nonamatic, copy) NSMutableString *mStr;
_mStr = [[NSMutableString alloc] init];
这里是直接赋值,mStr还是得到一个可变类型的结果,但是
self.mStr = [[NSMutableString alloc] init];
如果使用了self. 那么将会调用setter方法,则mStr将会得到一个不可变类型的结果 __NSCFConstantString,按照原意mStr是可以改变的,而这里mStr的类型已经变为不可变类型了,此时再对其进行append等操作,则会crash
这就是为什么NS* 使用copy修饰,而NSMutable*则使用strong修饰的原因了
那么这里为什么类型会变呢,明明声明定义的是NSMutableString类型的属性,为什么结果得到的却不是呢,这里就需要了解另外一个概念--类簇
-- Thusday, 13 July 2017
网友评论