属性修饰符
区别
1.retain:
类似于ARC下的 strong
,表示强引用和持有的关系:将属性成员变量的指针指向源对象,同时持有源对象(此对象的引用计数会加1)。
1 |
|
2.assign:
类似于ARC下的 weak
,表示弱引用和不持有的关系:将属性成员变量的指针指向源对象,但不持有源对象,不更改其引用计数,一般用于基本数据类型(NSInteger
,CGFloat
)和C类型、int,float,double,bool
等,这些数值主要存在于栈上)。
1 |
|
weak 与 assign 的区别:
1、修饰的对象
assign 可修饰对象类型和基本类型,一般用于修饰基本类型。weak 只可以修饰对象类型,修饰基本数据类型时编译器会报错。
2、修饰对象类型时是否产生野指针
weak 不会产生野指针问题:weak 修饰的对象释放后指针会自动被置nil,之后再向该对象发消息也不会崩溃。assign 修饰对象类型时可能会产生野指针问题:assign 修饰的象被释放后指针不会自动被置空,此时向对象发消息会崩溃。另外,如果assign只是修饰基本数据类型,则是安全的。
3、小结:
值类型会被放入栈中,遵循先进后出原则,由系统负责管理栈内存。而引用类型会被放入堆中,需要我们手动管理内存或通过ARC管理。weak 适用于 delegate 和 block 等引用类型,不会导致野指针问题,是安全的,可用于解决循环引用问题。assign 适用于基本数据类型,不适用于引用类型。
3.copy:
表示拷贝和持有:会在内存中拷贝一份源对象,并将属性对应的成员变量的指针指向此拷贝出的新对象,新对象的引用计数 = 1。
1 |
|
与 strong 的区别在于:strong
修饰的变量与原对象指向同一片内存空间,对变量的修改会影响到源对象。而copy
修饰的对象与源对象指向两片不同的内存空间,变量与原对象两者互不影响。
4.readwrite:
编译器自动为属性创建 setter/getter 方法。
5.readonly:
编译器只为属性创建 getter 方法。
属性被声明为只读时,可以同时重写属性的getter
与setter
使其变为 readwrite。
6.nonatomic:
nonatomic 修饰的对象不保证setter
和getter
的完整性,多线程中访问它时可能会返回未初始化的对象。它比atomic
快,但它不是线程安全的。
1 |
|
7.atomic:
atomic 修饰的对象会保证setter
和getter
的完整性,任何线程对其访问都可以得到一个完整的初始化后的对象。例如有多个线程同时调用setter
,不会出现某个线程执行完setter
全部语句之前,另一个线程开始执行setter
情况,相当于函数头尾加了锁一样。
1 |
|
因为要保证操作完成,所以速度慢。它比nonatomic
安全,但也并不是绝对的线程安全,例如多个线程同时调用set
和get
就会导致获得的对象值不一样甚至发生崩溃。绝对的线程安全就要用到线程的同步机制,比如使用NSLock
、@synchronized
等加锁。
8.默认值
基本数据类型的默认关键字是:atomic
、readwrite
、assign
;
属性的默认关键字是:atomic
、readwrite
、strong
。
Getter与Setter
@dynamic
1 |
|
@dynamic:告诉编译器,属性的getter
和setter
由我们自己实现,不需要编译器自动生成。如果我们将属性标记为@dynamic var;
而又没有提供对应的getter
与setter
时,编译期是不会报错,但在运行期如果访问属性或者给属性赋值时则会报错并崩溃,因为运行时找不到对应的getter
和setter
去完成这两个操作。
@synthesize
1 |
|
@synthesize:告诉编译器,在编译期用我指定的成员变量实现属性的getter
和setter
。
1 |
|
注意上面访问属性时使用的都是self.anArr
,这时如果使用_anArr
会报错,因为@synthesize anArr;
只创建了成员变量anArr
并绑定到属性anArr
上。所以需要我们使用@synthesize anArr = _anArr
来让编译器帮我们创建成员变量_anArr
并将其绑定到属性上。
默认值
iOS5之后,如果@synthesize
和@dynamic
都没写,那么属性默认是@syntheszie var = _var
;
相关参考: