属性关键字分类
#属性关键字可以分为三类#
//带星标的为默认
1.读写权限: *readwrite readonly
2.原子性: *atomic nonatomic
3.引用计数
*strong(ARC) / return(MRC) #这两个关键字都是用来修饰对象
*assign / unsafe_unretained(MRC) #assign既可以修饰基本数据类型,也可以修饰对象类型
weak
copy
#备注#
atomic修饰的属性: 可以保证对该成员变量的赋值和获取数据是线程安全的
栗子🌰
如果我们用atomic修饰了一个数组,那么对这个数组进行赋值和获取,是可以保证线程安全的
但如果我们对数组进行操作,添加或移除对象,那么是不在atomic的负责范围内,所以是没有办法保证线程安全的
assign
- 修饰基本数据类型,如int, BOOL等
- 修饰对象类型时,不改变其引用计数
- 会产生悬垂指针: assign所修饰的对象,在被释放之后,assign指针仍指向原对象内存地址,如果这时通过assign指针,继续访问原对象,会导致内存泄露或程序异常
weak
- 不改变被修饰对象的引用计数,一般使用weak是用来解决循环引用问题
- 所修饰的对象在被释放之后会自动置为nil
weak和assign的区别
- weak可以修饰对象,assign既可以修饰对象,也可以修饰基本数据类型
- weak所修饰的对象,在被废弃之后,weak指针置为nil. assign所修饰的对象,在被释放之后,assign指针仍指向原对象内存地址
weak和assign的联系
在修饰对象时,weak和assign都不改变被修饰对象的引用计数
weak所修饰的对象,在被废弃之后,为什么置为nil(内存管理)
copy
#NSMutableArray用copy修饰会出现什么问题?#
@property (copy) NSMutableArray *array;
浅拷贝:是指针拷贝,是对内存地址的复制,让目标对象指针和源对象指向同一片内存空间

指针A指向某个对象的内存,对象在内存当中用黑框表示,若此时对对象A进行浅拷贝,就会有个B指针指向和A同一块的内存地址
所以说,浅拷贝是对内存地址的复制,但是并没有对内存空间复制,A和B两个指针是指向了同一片内存空间
浅拷贝的特点
1.浅拷贝会增加被拷贝对象的引用计数,上图的引用计数就是2
2.并没有发生新的内存分配,两个指针指向同一块原来的内存空间
深拷贝:是内存拷贝,是让目标对象指针和源对象指针分别指向两片内容相同的内存空间

指针A指向某个对象的内存,对象在内存当中用黑框表示,若此时对对象A进行深拷贝,就会产生新的内存分配,然后会有一个新的指针B,指向这块新的内存
两片内存空间只是内容相同,但不是同一块内存空间
深拷贝的特点
- 不会增加被拷贝对象的引用计数,因为没有新指针指向原来的内存空间
- 产生了新的内存分配,出现了两块内存
深拷贝和浅拷贝的区别
-
是否开辟了新的内存空间
深拷贝开辟了新的内存空间,浅拷贝没有开辟 -
是否影响了引用计数
深拷贝没有影响,浅拷贝增加了引用计数
copy关键字的使用
- 可变对象的copy和mutableCopy都是深拷贝
- 不可变对象的copy是浅拷贝,mutableCopy是深拷贝
-
copy方法返回的都是不可变对象,若被拷贝对象是可变对象,返回的也是不可变对象
#NSMutableArray用copy修饰会出现什么问题?#
@property (copy) NSMutableArray *array;
若上面的NSMutableArray类型的array被copy修饰,会导致程序异常
因为如果赋值过来的是NSMutableArray对象A,会对可变对象A进行copy操作,拷贝结果是不可变的,那么copy后就是NSArray
如果赋值过来的是NSArray对象B,会对不可变对象B进行copy操作,拷贝结果仍是不可变的,那么copy之后仍是NSArray
所以不论赋值过来的是什么对象,只要对NSMutableArray进行copy操作,结果一定是不可变的
但因为原来属性声明的是NSMutableArray,就会调用添加或者移除方法
但因为拷贝后的结果是不可变对象,所以一旦调用这些方法就会程序崩溃!!!
MRC下如何重写retain修饰变量的setter方法
很多公司的app大多很早之前就产生了,那个时候,有很多文件是使用MRC的,所以需要了解MRC知识
@property (nonatomic, retain)id obj;
- (void)setObj:(id)obj
{
if (_obj != obj) {
[_obj release];
_obj = [obj retain];
}
}
/*
retain和内存管理相关
在set方法里先判断,如果传进来的对象不是原来的对象,那么要先对原来的对象进行release操作
然后对新传来的值进行retain操作,再赋值给成员变量
为什么先做不等的判断,不是因为避免相等情况下走多次造成不必要的开销.而是因为:
如果传递进来的obj对象恰好就是原来的对象的话,先对原对象进行release操作,实际上也是对传递进来的对象进行release操作
那么很可能传进来的这个obj对象就被我们无辜释放了,再做 [obj retain]就会异常
所以要做不等判断,主要是为了防止异常处理
*/
网友评论