1.什么是KVO?什么是KVC
-
KVO: Key-Value Observing,俗称“键-值 监听”,可用于监听对象的某一属性改变
KVO的简单使用.png
- KVC:Key-Value Coding,俗称“键值编码”,可以通过一个key来访问某个属性
2.KVO的本质是什么?
- 利用runtime消息发送机制动态创建NSNotify_XX子类,子类拥有自己的set方法实现
- 在子类setter方法中实质是调用NSKeyValueObserving,
set方法实现内部会顺序调用willChangeValueForKey方法、原来的setter方法实现、didChangeValueForKey方法,而didChangeValueForKey方法内部又会调用监听器的observeValueForKeyPath:ofObject:change:context:监听方法 - 在observeDidChange方法中----observeValueForKeyPath:ofObject:change:context:监听方法
3.如何手动触发KVO
- 先要手动调用willChangeValueForKey
- 再调用DidChangeValueForKey
4.直接修改成员变量会触发KVO吗?
- 不会
5.通过KVC修改属性会触发KVO吗? - 不会
6.KVC的赋值和取值过程?查找顺序?实现原理?
事实证明再也找不到比MJ 总结的更详细的KVC了!!!
weak原理:Runtime维护了一个Weak表,用于存储指向某个对象的所有Weak指针。Weak表其实是一个哈希表,Key是所指对象的地址,Value是Weak指针的地址(这个地址的值是所指对象的地址)的数组。
一个对象A,里面有一个weak属性B, 首先会有一个hash表, 键为A的地址, 值为一个数组, 这个数组里包含了B指针的地址, 当销毁的时候回根据B指针的地址获取到B的指针, 然后置为nil
在对象被回收的时候,经过层层调用,会最终触发下面的方法将所有Weak指针的值设为nil。
简单来说,这个方法首先根据对象地址获取所以Weak指针地址的数组,然后遍历这个数组把其中的数据设为nil,最后把这个entry从Weak表中删除。
1.初始化时:runtime会调用objc_initWeak函数,初始化一个新的weak指针指向对象的地址。
2.添加引用时:objc_initWeak函数会调用 storeWeak() 函数, storeWeak() 的作用是更新指针指向,创建对应的弱引用表。
3.释放时,调用clearDeallocating函数。clearDeallocating函数首先根据对象地址获取所有weak指针地址的数组,然后遍历这个数组把其中的数据设为nil,最后把这个entry从weak表中删除,最后清理对象的记录。
-
block的实现原理,__block的作用以及底层实现原理,block的循环引用问题,下划线修饰的变量会造成循环引用吗?怎么处理?masonry链式编程怎么实现的?什么情况下不用__weak?(Masonry、AFNetWorking、动画等)
block对象就是一个结构体,里面有isa指针指向自己的类(global malloc stack),有desc结构体描述block的信息,__forwarding指向自己或堆上自己的地址,如果block对象截获变量,这些变量也会出现在block结构体中。最重要的block结构体有一个函数指针,指向block代码块。block结构体的构造函数的参数,包括函数指针,描述block的结构体,自动截获的变量(全局变量不用截获),引用到的__block变量。(__block对象也会转变成结构体)
block代码块在编译的时候会生成一个函数,函数第一个参数是前面说到的block对象结构体指针。执行block,相当于执行block里面__forwarding里面的函数指针。
__block:Block不允许修改外部变量的值,这里所说的外部变量的值,指的是栈中指针的内存地址。__block 所起到的作用就是只要观察到该变量被 block 所持有,就将“外部变量”在栈中的内存地址放到了堆中。进而在block内部也可以修改外部变量的值。
block循环引用,指针相互指向,用__weak增加弱环
masonry链式编程:不会造成循环引用,constraintMaker只是局部变量,不会造成循环引用,链式编程:利用block, 代码块的返回类型是该类的实例变量,设置完相关的操作,并把实例对象返回。