1.内存管理
-
assign:
1.既可以修饰基本数据类型,也可以修饰对象类型;
2.setter方法的实现是基本赋值,一般用于基本数据结构;
3.修饰基本数据类型,如NSInterger、BOOL、int、float等;
4.修饰对象类型时,不增加其引用计数;
5.会产生垂悬指针,assign修饰的对象在被释放之后,指针仍然指向原对象地址,该指针变为垂悬指针。这时候如果继续通过该指针访问原对象的话,就可能导致程序崩溃。 -
weak:
1.只能修饰对象类型;
2.ARC下才能使用;
3.修饰弱引用,不增加对象引用计数,主要可以用于避免循环引用;
4.weak修饰的对象在被释放之后,会自动将指针置为nil,不会产生悬垂指针; -
retain:
1.MRC下使用,ARC下使用strong;
2.修饰强引用,将指针原来指向的旧对象释放掉,然后指向新对象,同时将新对象的引用计数加1;
3.setter方法的实现是release旧值,retain新值,用于oc对象类型; -
strong:
1.ARC下才能使用;
2.原理同retain ;
3.但是在修饰block时,strong相当于copy,而retain相当于assgin; -
copy:
1.setter方法的实现是release旧值,copy新值,用于NSString、block等类型; 2.copy分为深拷贝和浅拷贝;
2.所有权修饰符
- __strong:
1.强引用持有对象,可以对应strong、retain、copy关键字;
2.编译器将为strong、retain、copy修饰的属性生成带__strong所有权修饰符的实例变量; - __weak:
1.弱引用持有对象,对应weak关键字,ARC下用来防止循环引用;
2.编译器将为weak修饰的属性生成带__weak所有修饰符的实例变量; - __unsafe_unretained:
1.弱引用持有对象,对应unsafe_unretained、assgin关键字,MRC下用来防止循环引用;
2.编译器将为unsafe_unretained修饰的属性生成带__unsafe_unretained所有修饰符的实例变量;
3.与__weak相比,它不需要遍历weak表来检查对象是否nil,性能上要更好一些。但是它会产生悬垂指针; - _autoreleasing:
1.在MRC中我们可以给对象发送autorelease消息将它注册到autoreleasepool中,而在ARC中我们可以使用__autoreleasing修饰符修饰对象将对象注册到autoreleasepool中;
3.深浅拷贝
- 浅拷贝:
指针拷贝,赋值一个新的指针,只能同一块内存区域,实际内存并没有发生拷贝,当内存销毁的时候,指向这片内存的几个指针需要重新定义才可以使用,要不然会成为野指针。
浅拷贝就是拷贝指向原来对象的指针,使原对象的引用计数+1,可以理解为创建了一个指向原对象的新指针而已,并没有创建一个全新的对象。 - 深拷贝:
内容拷贝,拷贝数据到一块新内存区域,指针指向拷贝的数据区。深拷贝是指拷贝对象的具体内容,而内存地址是自主分配的,拷贝结束之后,两个对象虽然存的值是相同的,但是内存地址不一样,两个对象也互不影响,互不干涉。
深拷贝就是拷贝出和原来仅仅是值一样,但是内存地址完全不一样的新对象,创建后和原对象没有任何关系。 - 总结:
深拷贝就是内容拷贝,浅拷贝就是指针拷贝,本质区别在于:- 是否开启新的内存地址
- 是否影响内存地址的引用计数
- 可变对象的copy和mutablecopy方法都是深拷贝
- 不可变对象的copy方法是浅拷贝
- copy方法返回的对象都是不可变对象

4.面试题
- 以下代码会出现什么问题?
@property (copy) NSMutableArray *array;
答案:不论赋值过来的是NSMuatbleArray还是NSArray对象,进行copy操作后都是NSArray对象(深拷贝)。由于属性被声明为NSMutableArray类型,就不可避免的会有调用方去调用它的添加对象、移除对象等一些方法,此时由于copy的结果是NSArray不可变对象,对NSArray对象调用添加对象、移除对象等方法,就会产生程序异常。
- 为什么NSString使用copy ?
使用copy修饰之后,即使属性拷贝来自可变字符串,也会被深拷贝成不可变字符串,也就是源字符串修改之后不会影响到属性字符串,增强代码的健壮性。