目录
二、assign、strong、retain、weak、copy和unsafe_unretained
一、nonatomic与atomic
决定编译器生成的getter和setter是否为原子操作(即是否线程安全),也可以理解为属性是否适合在多线程的场景下使用。
atomic:在声明属性的时候,默认选择的是该属性。该属性是一个原子属性,使用了这个属性后,系统生成的 getter/setter 会保证 get、set 操作的完整性,不受其他线程影响。getter 总是能得到一个完好无损的对象(可以保证数据的完整性),具体的实现方法是编译器会自动生成一些互斥加锁代码,如果发现有其它线程正在执行锁定的代码,线程会用死循环的方式,一直等待锁定的代码执行完成,以此避免读写不同步问题。
nonatomic:该属性是一个非原子属性,如果该对象无需考虑多线程的情况,可以加入这个属性,这样会让编译器少生成一些互斥加锁代码,可以提高效率。nonatomic返回的对象可能不是完整的value,但nonatomic的处理速度要比atomic快。
OC中的锁:互斥锁和自旋锁
共同点:使程序在同一时间只有一个线程访问
互斥锁:1.读写方法都是线程安全的
2.如果发现其他线程正在执行锁定代码,线程会进入休眠(就绪状态),等其它线程时间片到打开锁后,线程会被唤醒(执行)。
自旋锁:1.单写多读,即写的时候是线程安全的,但是读的时候是非线程安全的
2.如果发现有其他线程正在执行锁定的代码,就会进入到死循环,直到被锁定的代码执行完成,自旋锁更适合执行不耗时的代码
二、assign、strong、retain、weak、copy和unsafe_unretained
这几个关键字是内存管理特性,可以决定程序的引用计数类型。
assign:对属性只是简单赋值,不更改对所赋的值的引用计数,这个指示符主要适用于NSInteger等基本类型,以及short、float、double、结构体等各种C数据类型。它是一个弱引用声明类型,我们一般不使用assign来修饰对象,因为被assign修饰的对象,在被释放掉以后,指针的地址还是存在的,也就是说指针不会被置为nil,造成野指针,可能导致程序崩掉。那为什么assign就能用来修饰基本数据类型呢,是因为基本数据类型一般分布在栈上,栈的内存会由系统自动处理,因此不会造成野指针。
weak:该属性也是一个弱引用声明类型,使用weak修饰的对象是不会造成引用计数器+1的,并且引用的对象如果被释放了以后会自动变成nil,不会出现野指针,很好的解决了内存引起的崩溃情况。通常我们会在block和协议的时候使用weak修饰,通过这样的修饰,我们可以规避掉循环引用的问题。
strong:该属性是一个强引用声明类型,只要该强引用指向被赋值的对象,那么该对象就不会自动回收。
retain:释放旧的对象,将旧对象的值赋予输入对象,再提高输入对象的索引计数为1;在ARC模式下很少使用,通常用于指针变量,就是说你定义了一个变量,然后这个变量在程序的运行过程当中会改变,并且影响到其他方法。一般用于字符串、数组等
copy:若使用copy指示符,则调用setter方法给变量赋值的时候,会将被赋值的对象复制一个副本,再将该副本赋值给成员变量。copy指示符会将原成员变量所引用对象的计数减1。
相当于就是说,不用copy的话,会创建一个新的空间,它的内容和原对象内容一模一样,然后指针是指向新空间的。当再有什么操作在对那个对象操作的话,只是在原空间上操作,对新空间没有影响。当成员变量的类型是可变类型,或其子类是可变类型的时候,被赋值的对象有可能在赋值后被修改,如果程序不需要这种修改影响setter方法设置的成员变量的值,此时就可考虑用copy指示符。
copy与retain的区别:
copy是创建一个新对象,retain是创建一个指针,引用对象计数加1。
eg: 一个NSString 对象,地址为0×1111 ,内容为@”STR”
Copy 到另外一个NSString 之后,地址为0×2222 ,内容相同,新的对象retain为1 ,旧有对象没有变化
retain 到另外一个NSString 之后,地址相同(建立一个指针,指针拷贝),内容当然相同,这个对象的retain值+1
也就是说,retain 是指针拷贝,copy 是内容拷贝。
unsafe_unretained:类似于assign,在离开作用域后不会自动赋值为nil,适用于“对象类型”,该特质表达一种“非持有关系” 。unsafe_unretained
与其他几种属性关键字的区别在于引用计数类型不同。unsafe_unretained
表示不可变的指针引用,不会自动释放内存,需要手动释放。strong
表示可变的指针引用,会自动释放内存;weak
表示弱引用,不会增加引用计数,当对象被释放时,弱引用会自动变为nil
。另外,copy
和retain
表示指针拷贝,会增加引用计数,而assign
表示指针赋值,不会增加引用计数。
强引用和弱引用:OC里ARC中的强引用和弱引用_oc 强引用例_AlgolStep的博客-CSDN博客
深浅拷贝:OC学习之——Foundation框架_晓美焰丶的博客-CSDN博客——深复制与浅复制
strong和copy的区别:用一个实例说明:
首先,我们自定义一个Test类,该类有两个属性,都是可变字符串,属性关键字一个是copy一个是strong。
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface Test : NSObject
@property (nonatomic, copy) NSMutableString *strTest1;
@property (nonatomic, strong) NSMutableString *strTest2;
@end
NS_ASSUME_NONNULL_END
然后在主函数中创建一个该类的实例对象, 然后使用NSMutableString型变量对该实例对象中的两个属性赋值。
#import <Foundation/Foundation.h>
#import "Test.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
Test *t1 = [[Test alloc] init];
NSMutableString *str1 = [NSMutableString stringWithString:@"test1"];
t1.strTest1 = str1;
NSMutableString *str2 = [NSMutableString stringWithString:@"test2"];
t1.strTest2 = str2;
NSLog(@"%p",t1.strTest1);
NSLog(@"%p",str1);
NSLog(@"%p",t1.strTest2);
NSLog(@"%p",str2);
}
return 0;
}
结果发现:使用copy关键字的字符串属性的strTest1和str1的地址不相同,即没有指向同一个对象,这是一次深拷贝;而使用strong关键字的strTest2和str2的地址相同,即指向了同一个对象,这是一次浅拷贝。原因是我们前面说过,strong是一个强引用类型,因此str2会持有strTest2所持有的对象,并使strTest2的引用计数加一,此时就是一个浅拷贝,而copy就不会这样。这就是strong和copy的区别。
三、readonly和readwrite
这个就是访问权限的控制,决定该属性是否可读和可写,默认是readwrite
,所以我们定义属性的时候,一般不需要这个修饰。只有只读属性才需要加上readonly
的修饰。 readonly
来控制读写权限的方式就是只生成getter方法,不生成setter方法。