收录:空杯子
前面的话
属性关键字是iOS开发中的基础。 基础往往容易被忽略,但是细节决定成败。 如果面试时,忽然来一发属性关键字相关的问题,回答的不好,那给面试官的印象就会差很多,成为了木桶短板的一个。可能前面回答的好建立的优势就没了。
开始面试
我正在会议室略有紧张的等待面试,忽然看到一个穿着格子衬衫,大腹便便的中年男子拿着简历向我走来, 我看着他头上快要绝顶的头发,心想这肯定是个iOS开发技术牛逼闪闪的老前辈。
还好看过《iOS之一起进大厂》系列,我的知识很渊博,基础很牢固,不慌。刚紧张到提到嗓子眼的心,又按下去了。淡定从容,一点都不虚好伐,就是这么自信淡定。
我什么时候也能变成那样厉害的高手
面试官:
小伙子,看你简历 ,你对开发基础了解的很透彻啊,那咱们今天就聊聊属性关键字把。 你对属性关键字怎么理解?
属性关键字可以分为三种类型:
- 读写权限的类型: readonly ,readwrite
- 原子类 : atomic ,nonatomic
- 引用计数 : retain/strong/copy,assign/unsafe_unretained,weak
读写权限的类型: readonly ,readwrite
- readwrite 是可读可写特性;会自动生成getter方法和setter方法
- readonly 是只读特性 只会生成getter方法 ,不会生成setter方法
原子类: atomic nonatomic
atomic是保证赋值和获取是线程安全的。 这里说的是对成员属性的直接赋值和获取,并代表操作和访问。 对于atomic的属性,系统生成的 getter/setter 会保证 get、set 操作的完整性,不受其他线程影响。
retain关键字
只有在MRC的环境下使用。 retain引起对象的引用计数加1, release引起引用计数减1,当引用计数为0时,dealloc函数被调用,内存被回收。
那你说说strong和weak的区别是?
strong 表示指向并拥有该对象。其修饰的对象引用计数会加1.该对象只要引用计数不为0则不会被销毁。当然强制将其置为nil也可以销毁它。 weak 表示指向但不拥有该对象。其修饰的对象引用计数不会增加。无需手动设置,该对象会自行在内存中销毁。
如何理解的atomic的线程安全呢,有没有什么隐患?
atomic对一个数组,进行赋值或获取,是可以保证线程安全的。但是如果进行数组进行操作,比如给数据加对象或移除对象,是不在atomic的保证范围。
strong 和weak的区别?
strong 表示指向并拥有该对象。其修饰的对象引用计数会加1.该对象只要引用计数不为0则不会被销毁。当然强制将其置为nil也可以销毁它。 weak 表示指向但不拥有该对象。其修饰的对象引用计数不会增加。无需手动设置,该对象会自行在内存中销毁。
assign 和weak的区别有哪些?
assign修饰基础数据类型,int, BOOL
assign修饰对象类型,不改变对象的引用计数。
assign 会产生悬垂指针, assign 的对象被释放之后,对象指针还是会指向原来的地址,会产生悬垂指针 ,导致程序内存泄露和程序崩溃。
weak不改变修饰对象的引用计数
所指向的对象在被释放后自动设置为 nil.
他们的区别:
1、assign可以修饰对象和基本数据类型, weak只修饰对象
2、assign 所修饰的对象被释放后,还会指向原对象内存地址。weak 所修饰的对象被废弃之后,weak 所修饰对象会被设置为nil。
但是他们有一个共同点,他们都不会改变修饰对象的引用计数。
copy关键字影响了对象的可变和不可变属性吗?
可变对象(mutable)copy和mutableCopy都是深拷贝 不可变对象(immutable)的copy是浅拷贝,mutableCopy是深拷贝 copy方法返回的都是不可变对象,若被拷贝对象是可变对象,返回的也是不可变对象。 例子解析如下:
浅拷贝和深拷贝的区别?
浅拷贝只是对 内存地址的复制,两个指针指向同一个地址,增加被拷贝对象的引用计数,没有发生新的内存分配。
深拷贝:目标对象指针和源对象指针,指向两片内容相同的内存空间。
2个特点:不会增加被拷贝对象的引用计数,产生了新内存分配,出现了2块内存。
总结区别:
浅拷贝增加引用计数,不产生新的内存。
深拷贝不增加引用结束,会新分配内存
NSMutableArray用copy修饰会出现什么问题?
出现调用可变方法不可控问题,会导致程序崩溃。 具体原因如下:
给Mutable 被声明为copy修饰的属性赋值, 过程描述如下:
1.如果赋值过来的是NSMutableArray对象,会对可变对象进行copy操作,拷贝结果是不可变的,那么copy后就是NSArray
2.如果赋值过来的是NSArray对象, 会对不可变对象进行copy操作,拷贝结果仍是不可变的,那么copy之后仍是NSArray。
所以不论赋值过来的是什么对象,只要对NSMutableArray进行copy操作,返回的对象都是不可变的。
那原来属性声明的是NSMutableArray,可能会调用了add或者remove方法,拷贝后的结果是不可变对象,所以一旦调用这些方法就会程序崩溃(crash)
MRC下如何重写retain修饰变量的setter方法?
这里关键点在于,如果恰好设置的是原来的对象,不做判断的话,就会导致把自己对象给释放了,会导致程序访问异常。所以需要先做判断。
weak属性修饰的变量,如何实现在变量没有强引用后自动置为 nil ?
runtime 维护了一个weak_table_t 弱引用表 ,用于存储指向某一个对象的所有weak指针。weak表其实是一个哈希表,
key是所指对象的地址,value是weak指针的地址的数组。
在对象回收的时候,根据对象的地址将所有weak指针地址的数组,遍历数组把其中的数据置为nil
__weak 和 _Unsafe_Unretain 的区别?
weak 修饰的指针变量,在指向的内存地址销毁后,会在 Runtime 的机制下,自动置为 nil。
_Unsafe_Unretain不会置为 nil,容易出现 悬垂指针,发生崩溃。但是 _Unsafe_Unretain 比 __weak 效率高。
坚持看到这里的同学,你们个个都是人才,我好喜欢。