@dynamic 告诉编译器由我们自己来实现访问方法。
@synthesize 告诉编译器帮忙实现访问方法。
readonly此标记说明属性是只读的。如果你指定了只读,在@implementation中只需要一个读取器。或者如果你使用@synthesize关键字,也是有读取器方法被解析。而且如果你试图使用点操作符为属性赋值,你将得到一个编译错误。但是可以使用成员变量的方法去赋值。
readwrite此标记说明属性会被当成读写的,这也是默认属性。设置器和读取器都需要在@implementation中实现。如果使用@synthesize关键字,读取器和设置器都会被解析。
nonatomic:非原子性访问,对属性赋值的时候不加锁,多线程并发访问会提高性能。默认是atomic。
加了atomic,访问方法在开始和结尾会加锁。atomic不是一定线程安全的。只是属性的存取方法是线程安全的,并不保证整个对象是线程安全的。比如 两个线程都拿到了一个数组对象 一个线程进行数据删除,一个进行数据遍历,就有可能crash。
assign: 简单赋值,不更改索引计数
copy:建立一个索引计数为1的对象,然后释放旧对象,被拷贝的对象没有影响。
retain:释放旧的对象,将旧对象的值赋予输入对象,再提高输入对象的索引计数为1
copy与retain:
Copy会新建一个内容相同的对象,而retain不会创建新对象:
比如一个NSString对象,地址为0×1111,内容为@”STR”
Copy到另外一个NSString之后,地址为0×2222,内容相同,新的对象retain为1,旧有对象没有变化
retain到另外一个NSString之后,地址相同(建立一个指针,指针拷贝),内容当然相同,这个对象的retain值+1
retain是指针拷贝,copy是内容拷贝。
weak:声明的变量在栈中就会自动清空,赋值为nil。
strong:强引用,会将数据和内存地址同时引用过来。
unsafe_unretained:类似于assign,在离开作用域后不会自动赋值为nil。
在ARC模式下,指针变量都用weak修饰,只有基本数据类型和结构体需要用assgin,例如delegate,NSInteger。
block和string使用copy。
nonnull:属性不能为空
nullable:属性可以为空
null_resettable:声明属性set方法可以为nil,但是get一定不能为nil
null_unspecified:不确定属性是否为空
NS_ASSUME_NONNULL_BEGIN -- NS_ASSUME_NONNULL_END标签:则是声明夹在标签中间的属性,默认都是nonnull。
assign可以用于OC对象吗?
不可以。assign一般是用于修饰基本数据类型和oc数据类型。
基本数据类型和oc数据类型的内存一般被分配在栈上,而对象的内存一般被分配到堆上,栈上的内存有系统分配和释放,堆上的则有程序员管理。
所以,这可能造成在该对象被释放后,该指针仍然会指向对象的内存地址,不会自动设置为nil,而当后续这块内存地址被使用就会造成崩溃。
weak如何实现自动赋nil?
Runtime维护了一个Weak表,用于存储指向某个对象的所有Weak指针。Weak表其实是一个哈希表,Key是所指对象的地址,Value是Weak指针的地址(这个地址的值是所指对象的地址)的数组。在对象被释放的时候,首先会根据对象地址获取所有Weak指针地址的数组,然后遍历这个数组把其中的数据设为nil,最后把这个entry从Weak表中删除。