面试题:weak实现原理?
一、weak
weak 基本用法
weak 是弱引用,用 weak 来修饰、描述所引用对象的计数器并不会增加,而且 weak 会在引用对象被释放的时候自动置为 nil,这也就避免了野指针访问坏内存而引起奔溃的情况,另外 weak 也可以解决循环引用。
为什么修饰代理使用 weak 而不是用 assign?
assign 可用来修饰基本数据类型,也可修饰 OC 的对象,但如果用 assign 修饰对象类型指向的是一个强指针,当指向的这个指针释放之后,它仍指向这块内存,必须要手动给置为 nil,否则会产生野指针,如果还通过此指针操作那块内存,会导致 EXC_BAD_ACCESS 错误,调用了已经被释放的内存空间;而 weak 只能用来修饰 OC 对象,而且相比 assign 比较安全,如果指向的对象消失了,那么它会自动置为 nil,不会导致野指针。
weak 原理概括
weak 表其实是一个哈希表,key 是所指对象的指针,value 是 weak 指针的地址数组。(value 是数组的原因是:因为一个对象可能被多个弱引用指针指向)
Runtime 维护了一张 weak 表,用来存储某个对象的所有的 weak 指针。
2、strong
strong表示属性对修饰的对象有一个强引用,会先保留新值,然后释放旧值。只能修饰对象
weak表示属性对修饰的对象有一个弱引用,对于新值不会增加引用计数,对于旧值也不会减少引用计数。当修饰的对象被释放时,weak修饰的属性被自动被置为nil,能够有效防止野指针错误。
weak常用于防止循环引用
3、@property 深入理解
@property = ivar + getter + setter
其中ivar是实例变量,编译器会帮我们自动生成名字为‘_属性名’这样的实例变量,同时自动生成getter和setter方法。
编译器帮我们做的事情
当我们声明一个属性后,编译器会将当前关键字修饰的属性自动生成setter方法和getter方法。
@property (nonatamic, copy) NSString *name; 等价于
-(void)setName:(NSString*)name{_name=name.copy;}
-(NSString*)name{return_name;}
编译器以上的工作我们称之为属性自动合成
@synthesis
iOS6以后LLVM编译器引入property autosynthesis,即属性自动合成,就是编译器会为每个@property添加@synthesis,如下
@synthesize propertyName = _propertyName;
如果不存在_propertyName实例变量,则会创建一个_propertyName,如果已经存在,则不会添加实例变量
@synthesis使用场景
以下场景自动合成会失效,需要手动合成
什么情况下自动合成会失效 ?
同时重写了属性的setter和getter时;
重写了只读属性的getter时;
使用了@dynamic时;
在@protocol中定义的所有属性;
在 category 中定义的所有属性;
父类已有的属性,子类重载的属性不会自动合成;
@dynamic
@dynamic 告诉编译器,不要为property声明的属性添加setter/getter方法, 由用户自己实现,该属性的getter和setter方法可能不在本类,而在其他地方(比如父类或者在运行时中提供, 如果不实现的话, 运行时会有Unrecoginzed Selector Crash)