<iOS知识体系>属性关键字和修饰符

245 阅读4分钟

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修饰之后,即使属性拷贝来自可变字符串,也会被深拷贝成不可变字符串,也就是源字符串修改之后不会影响到属性字符串,增强代码的健壮性。