关键字可以分为以下六类
- 修饰器类型:@property、@synthesize、@dynamic
- 原子安全类型: nonatomic、atomic
- 计数引用类型: strong、weak、assign、copy、retain、unsafe_unretained
- 读写类型:readonly,readwrite
- 访问类型:extern、static、const
- 局部引用类型:__weak、__block、__strong
1、修饰器类型:@property、@synthesize、@dynamic
1.1@property
@property (nonatomic,copy) NSString *str;
用来声明属性,相当于声明了_str,并且默认实现了str的getter和setter方法
1.2synthesize
#import "ClassA.h"@interface ClassA()@property NSString * str3;@end@implementation ClassA
// 或者写成 @synthesize str3
@synthesize str3 = str4;@end
@synthesize要用的话,必须得声明了同名的属性,例如我已经声明了str3,再用@synthesize声明str3,那么就相当于编译器默认生成了一个str3属性和一个str3成员变量.str3的getter个setter实际上操作的都是str4
1.3@dynamic
@dynamic声明属性就相当于告诉编译器不用生成属性的getter和setter方法,该属性的getter和setter方法由我自己生成
2、原子安全类型: nonatomic、atomic
这两个类型就是跟线程相关的,atomic与nonatomicd的主要区别就是系统自动生成的getter/setter方法不一样。
2.1、nonatomic
nonatomic(默认情况)表示非原子属性,也就是线程不安全类型,系统自动生成的getter/setter方法不会进行加锁操作。其内部的具体实现如下:
@property (nonatomic,strong) UIImage *image0;
@synthesize image0 = _image0;
/// MRC模式下- (UIImage *)image0{return _image0;
}- (void)setImage0:(UIImage *)image0 {if (_image0 != image0) {[_image0 release];_image0 = [[image0 retain] autorelease];}
}
2.2、atomic
atomic表示原子属性,表示线程安全,系统自动生成的getter/setter方法会进行加锁操作。其内部的具体实现如下:
@property (atomic,strong) UIImage *image1;
@synthesize image1 = _image1;
/// MRC模式下- (UIImage *)image1 {@synchronized (self) {return _image1;}
}- (void)setImage1:(UIImage *)image1 {@synchronized (self) {if (_image1 != image1) {[_image1 release];_image1 = [[image1 retain]autorelease];}}
}
atomic修饰的属性也不一定安全,当修饰NSMutableArray时,当我们进行remove和add的时候,此时也不是线程安全的,它不是原子操作。它保证的是getter和setter的线程安全。
3、计数引用类型: strong、weak、assign、copy、retain、unsafe_unretained
3.1 strong
当使用strong关键字修饰一个属性时,该属性不仅指向该对象,而且拥有该对象。该对象的引用计数会加1,属于强引用用。在ARC环境下,相当于retain。也称为浅拷贝(指针拷贝)。内存地址不变,只是生成了一个新的指针,新指针和引用对象的指针指向同一个地址。
注意:因为使用的是同一个内存地址,当该内存地址存储的内容发生变更的时候。属性也会变更。
3.2weak
同样经常用于修饰OC对象类型的数据,修饰的对象在释放后,指针地址会自动被置为nil,这是一种弱引用。
注意:在ARC环境下,为了避免循环引用,会把delegate属性用weak修饰,在MRC环境下使用assign修饰。当一个strong类型的指针不在指向它的时候,它就会被释放,即使还有weak的指针指向他,这些weak指针也会被值为nil。
weak属性修饰的变量,如何实现在变量没有强引用后自动置为 nil ?
runtime 维护了一个weak_table_t 弱引用表
,用于存储指向某一个对象的所有weak指针。weak表其实是一个哈希表,key是所指对象的地址,value是weak指针的地址的数组。在对象回收的时候,根据对象的地址将所有weak指针地址的数组,遍历数组把其中的数据置为nil。
3.3 assign
一般用来修饰非指针变量,用于基础数据类型 (例如NSInteger)和C数据类型(int, float, double, char, 等),另外还有id类型。也可用来修饰对象,但被assign修饰的额对象被释放后后,指针还是指针对象之前的地址,就变成了野指针。(如果用了assign修饰的对象,需要在dealloc函数中将该对象指针手动值为nil,可以消除野指针。
3.4 copy
copy和strong相同点在于都是属于强引用,都会是属性的计数加一,但是copy和strong不同点在于,它所修饰的属性当引用一个属性值时,是内存拷贝(深拷贝),就是在引用是,会生成一个新的内存地址和指针地址来,和引用对象完全没有相同点,因此它不会因为引用属性的变更而改变(当引用的属性值是不可变对象时,是浅拷贝)
具体的用例可以参考:strong和copy的区别
copy修饰的关键字不同在于属性setter的有一个关键语句:
_copyyStr = [copyyStr copy];
所以只有在用点语法赋值时copy关键字才会生效
@property (copy) NSMutableString* name;
如果用copy来修饰NSMutableArray,NSMutableDictionary,NSMutableString这种不可变对象会导致问题,初始化后通过copy生成的是该类型对应的不可变对象,例如NSArray、NSDictionary、NSString。如果我们按照可变对象进行修改属性操作,就有可能报错。
3.5 retain
retain主要用在MRC模式下,作用和strong几乎等同
3.6 unsafe_unretained
unsafe_unretained类型指针指向一块内存时,内存的引用计数也不会增加,这一点与weak一致。但是与weak类型不同的是,当其所指向的内存被销毁时,unsafe_unretained类型的指针并不会被赋值为nil,也就是变成了一个野指针。对野指针指向的内存进行读写,程序就会crash
4,读写类型 readonly readwrite
4.1 readonly
readonly相当于是系统只会默认生成该属性的getter方法,只可读不可写,用点属性的形式去赋值,那么就会编译报错。
如果是在该类的外部访问readonly属性,利用kvc直接赋值。可以通过在类的内部重写accessInstanceVariablesDirectly,固定返回No,那么外界就无法再通过kvc形式来更改
4.2 readwrite
readwrite就是声明该属性可读可写,一般默认就是readwrite,可以不用额外声明
5, 访问类型
5.1 extern
对于跨文件访问全局变量需要借助extern关键字声明,通过extern有两种方式可以访问其他文件的全局变量。
方式一
我们想要在B类访问A类中声明和定义的全局变量时,不导入A类的头文件,在B类中使用extern声明A类中的全局变量
方式二
我们在A.m文件中声明和定义的全局变量时,同时在A.h文件中做extern声明,在B类访问A类中全局变量时导入A的头文件就可以了,这种方式在代码中比较常见。
5.2 static
static除了可以修饰全局变量,还可以修饰局部变量,被static修饰的变量叫做静态变量。
主要作用:
- 隐藏
当程序有多个文件时,将全局变量或函数的作用域的作用范围限制在当前文件,对其他文件隐藏 - 保持变量内容的持久化
将函数的局部变量储存在全局数据区,使它不会随着函数的调用结束而被销毁
5.3 const
const用于修饰指针变量和基本数据类型,const放在谁前面,谁就是常量不可在更改。
不管是extern声明的全局变量还是用static、const修饰的全局变量和局部变量,它们的生命周期都是从定义到程序结束。
6,局部引用类型:__weak,__strong,__unsafe_unretained,__autoreleasing
- __strong
-
- 强引用持有对象,可以对应 strong、retain、copy 关键字。
-
- 编译器将为 strong、retain、copy 修饰的属性生成带 __strong 所有权修饰符的实例变量.
- __weak
-
- 弱引用持有对象,对应 weak 关键字,ARC下用来防止循环引用。
-
- 编译器将为 weak 修饰的属性生成带 __weak 所有权修饰符的实例变量。
- __unsafe_unretained
-
- 弱引用持有对象,对应 unsafe_unretained、assign 关键字,MRC下用来防止循环引用。
-
- 编译器将为 unsafe_unretained 修饰的属性生成带 __unsafe_unretained 所有权修饰符的实例变量。
-
- 与 __weak 相比,它不需要遍历 weak 表来检查对象是否 nil,性能上要更好一些。但是它会产生悬垂指针
- __autoreleasing
+在 MRC 中我们可以给对象发送 autorelease 消息来将它注册到 autoreleasepool 中,而在 ARC 中我们可以使用 __autoreleasing 修饰符修饰对象将对象注册到 autoreleasepool 中。