@property是OC中用到的,最重要的key words。
我们经常看到assign,retain,copy和strong,weak nonatomic等关键字出现在它之后。这个背后必然有各种阴谋,必须弄清,不然又是个坑的节奏。
非ARC环境
现在基本都用ARC了,不过一切都是有发展轨迹的,最新的技术也是从这个发展过来的。
assign属性
assign做的事情其实就是拷贝了指针。让这个属性只是复制你所赋给它的值的指针。于是,它们就共同指向了同一个区域了。
当数据类型为int、float等原生类型时,可以使用assign,否则可能导致内存泄露。例如当使用malloc分配了一块内存,并把它的地址赋值给了指针a,后来如果希望指针b也共享这块内存,于是讲a赋值给(assgin)b。这时就用到了assgin,此时a和b指向同一块内存。但是现在问题出现了,当a不再需要这块内存时,能都直接释放呢?肯定是不能的,因为a并不知道b是否还在使用这块内存,如果a释放了,那么b在使用这块内存的时候引起程序crash掉。
一般,assign对基础数据类型 (例如NSInteger,CGFloat)和C数据类型(int, float, [double] 等简单数据类型适用
retain属性
retain属性就是为了解决上述问题而提出的,使用了引用计数(reference counting),还是上面那个例子,我们给那块内存设一个引用计数,当内存呗分配并且赋值给a时,引用计数是1.当把a赋值给b时引用计数增加到2.这时如果a不再使用这块内存,它只需要把引用计数减1,表明自己不再拥有这块内存。b不再使用这块内存时也把引用计数减1.当引用计数变为0的时候,代表该内存不再被任何指针所引用,系统可以直接释放掉。此时系统自动调用dealloc函数,内存被回收。
所以因为和引用计数相关,所以必须是支持引用计数的对象才行。一般是NS系的复杂对象玩意才能比较好的用这个。
copy属性
copy就是新创建一块内存区域,复制变量的内容进来。只是保证了变量的内容相同,内存区域并不同。
这里还涉及 深拷贝和 浅拷贝 相关的知识。
ARC环境
ARC环境下,strong代替retain.weak代替assign
weak(类似assign)
在ARC环境下,对象的销毁不会受到weak指针的指向而不被销毁。
同时,所有指向销毁对象的weak指针都将被置为nil。这个特性很有用,相信很多开发者都被指针指向已释放的对象所造成的EXC_BAD_ACCESS困扰过,使用ARC以后,不论是strong还是weak类型的指针,都不会再指向一个已经销毁的对象,从根本上解决了意外释放导致的crash。
strong(类似retain)
在ARC环境下,只要某一对象被一个strong指针指向,该对象就不会被销毁。如果对象没有被任何strong指针指向,那么就会被销毁。在默认情况下,所有的实例变量和局部变量都是strong类型的。可以说strong类型的指针在行为上跟非ARC下得retain是比较相似的
weak和strong的区别
- weak 和 strong 属性只有在你打开ARC时才会被要求使用,这时你是不能使用retain release autorelease 操作的,因为ARC会自动为你做好这些操作,但是你需要在对象属性上使用weak 和strong,其中strong就相当于retain属性,而weak相当于assign。
- 只有一种情况你需要使用weak(默认是strong),就是为了避免retain cycles(就是父类中含有子类{父类retain了子类},子类中又调用了父类{子类又retain了父类},这样都无法release)
- 声明为weak的指针,指针指向的地址一旦被释放,这些指针都将被赋值为nil。这样的好处能有效的防止野指针。
其他属性
读写
- readonly:属性是只读的,默认的标记是读写,如果你指定了只读,在@implementation中只需要一个读取器。或者如果你使用@synthesize关键字,也是有读取器方法被解析(只生成getter,setter不会被生成)
- readwrite:说明属性会被当成读写的,这也是默认属性。设置器和读取器都需要在@implementation中实现。如果使用@synthesize关键字,读取器和设置器都会被解析(getter和setter 都会被生成)
原子属性
- nonatomic:非原子性访问,对属性赋值的时候不加锁,多线程并发访问会提高性能。如果不加此属性,则默认是两个访问方法都为原子型事务访问;nonatomic是不能保证线程安全的。但是nonatomic比atomic速度要快。这也是为什么property基本上都用nonatomic了
- atomic: 默认属性。无atomic这个关键字,直接不加nonatomic就好。atomic是保证读取变量是线程安全的,即它会保证每次getter和setter的操作都会正确的执行完毕,而不用担心其它线程在你get的时候set,可以说保证了某种程度上的线程安全。 最后加上一句,仅仅靠atomic来保证线程安全是不可能的,要写出线程安全的代码,还是需要有同步和互斥机制。
@property的默认属性
readwrite,atomic(即不写nonatomic)
非ARC环境下, 默认为assign
在ARC环境下,默认为strong