assign 修饰符用来修饰值类型和 id 类型(一般是 delegate)的属性,需要注意的是如果 id 类型的属性的修饰符用了 assign, 当你不再需要这个属性时,你必须将 delegate 手动置空,防止野指针产生,这也是为什么 delegate 一般都用 weak 修饰的原因。
weak 和 strong 是 ARC 的产物,分别表示弱引用类型和强引用类型。在给 strong 修饰的属性赋值时,会将属性的指针指向新值的地址,同时持有这个新值(新值的引用计数被加1)。在给 weak 修饰的属性赋值时,只是简单地将属性的指针指向新值的地址,不会持有新值。
retain 在 ARC 下基本等同于 strong。
copy 表示强引用,但是不会持有新值,而是拷贝一份引用计数为1的值给属性。给这种修饰符修饰的属性赋值时,实际上是把 新值调用 copy 方法后的返回值 赋给属性。NSString 类型常常用 copy 修饰,就是防止修改某个对象后,对强引用这个对象的属性造成不必要影响。
引用类型默认的修饰符是 strong.
值类型的默认修饰符是 assign.
Copy 传入的不是值,是对象。
Copy只能用于那些实现了NSCopying这个协议的类,否则会崩溃。按照字面意思,Copy即拷贝一份。一般来说,用户自己定义并实现了NSCopying的类,Copy的作用是在内存上再开辟空间,然后将调用者拷贝进去,所以对调用对象来说,它的引用计数并没有变化。
另外值得注意的是,像一些不可变类型,如NSString,NSArray,NSDictionary,NSSet之类,Copy并不会在内存上开辟新空间,而是为调用者的引用计数+1,等同于Retain。
这里不得不提声明Property里的修饰词作用了,声明一个Property目的是为了让编译器为我们自动合成Setter和Getter方法,如果我们不想编译器帮我们合成的话,我们可以这么写(基于ARC):
{
NSString *_value;
}
- (void)setValue:(NSString *)value {
_value = value;
}
- (NSString *)value {
return _value;
}
上面这种写法是存在一定问题的,往后再讲解。
编译器为我们合成的实现大概是这样子:
@property (nonatomic, copy) NSString *value;
- (void)setValue:(NSString *)value {
_value = value.copy;
}
- (NSString *)value {
return _value;
}
注意这里的copy,如果不用Copy修饰的话,跟第一个实现类似。
考虑一下这段代码会发生什么事,如果没有修饰为Copy时:
NSMutableString *mString = [[NSMutableString alloc] initWithString:@"string"];
self.value = mString;
这里创建一个可变的字符串对象,并赋值给了一个声明为不可变的字符串对象。这样导致本来指向不可变字符串对象的value指向了一个可变字符串对象。
但如果用了Copy修饰,那么在赋值前,可变的字符串对象先Copy为不可变字符串对象,再赋值到value上,这样就可以避免一些不可避免错误发生。
所以对这些不可变类的声明需要用Copy而不是Strong
意思就是说 NSString,NSArray,NSDictionary,NSSet等 这些不可变的类都要用copy。
网友评论