ios面试底层题目
---------------------------------------------------------------------------------------------------------------------------------
1. ios用什么方式实现对一个对象的KVO
利用runtimeAPI生成一个子类,并且让instance对象的isa指针指向这个全新的子类
当修改instance的属性的时候,会调用Foundation的NSSetXXXValueAndNotify
willchangevalueforkey
父类原来的setter
didchangevalueforkey
内部触发监控器的监听方法(observerValueForKeyPath:ofObject:change)
且只有触发setter方法会触发KVO,直接修改成员变量并不会触发KVO
---------------------------------------------------------------------------------------------------------------------------------
2. KVC赋值和取值过程是怎么样的,原理是什么,通过KVC可以触发KVO吗
首先,通过KVC可以触发KVO
KVC的全称为key - value Coding 俗称键值编码,可以通过一个key去访问对应的属性
赋值的过程
使用KVC中的setValue forkeypath的方法,其会先寻找set(key)方法,如果该方法不存在,就会寻找_set(value)方法,如果找到了上述两种方法之一,那么就会传递参数,调用对应的方法,否则,查看accessinstanceVariablesDirectly方法的返回值(该方法标记是否可以访问成员变量,默认可以访问成员变量),如果该值为NO的话,抛出异常,如果该值为YES的话,按顺序依次查找_key,_iskey,key,iskey,如果找到了直接赋值
获取值的过程
使用KVC的的valueForkey的方法,首先会依次按照getKey,key,iskey,_key顺序调用方法,如果找到了对应方法,直接调用,没找到方法,查看accessinstanceVariablesDirectly的值,如果为no,抛出异常,如果为yes,同样按照顺序依次查找_key,_iskey,key,iskey
---------------------------------------------------------------------------------------------------------------------------------
3. category
category的处理加载过程
1. 通过runtime加载分类所有数据
2. 把所有分类方法,属性,协议数据,合并大一个大数组中,后面参与编译的分类数据排在前面
3. 将合并后的分类数据,插入到原来数据的前面
---------------------------------------------------------------------------------------------------------------------------------
category的实现原理
首先分类写的方法都会合并到对应的类对象和元类对象中,并且合并是在运行的时候进行的
再编译的时候会存放到对应的结构体,结构题包含几个变量,第一个变量为类名称,第二个为对象方法列表表,第三个为类方法列表,第四个为协议列表,第五个为实例属性列表
对于分类的方法列表,我们会将其添加到一个方法列表中,该方法列表是一个二维数组,然后新增一行存放分类的方法,其余类似
随后在运行的时候我们将其添加到类对应的方法列表中,注意,这里是先移动原来的数据到最后,然后再从头进行添加
如果多个分类中存在一个同名方法,优先调用最后一个分类的方法,即最后一个参与编译的方法优先调用,我们可以调整编译顺序来改变调用的方法
注意,只是找到了后不再找了,而不是将原来的方法覆盖了,可以通过方法列表查找到
---------------------------------------------------------------------------------------------------------------------------------
category和Class Extension的区别是什么
category是运行的时候,才将数据添加到类中
extension在编译的时候,数据就已经包含在类信息里面了,用来声明私有方法,私有属性
---------------------------------------------------------------------------------------------------------------------------------
load initialize方法的区别是什么,他们再category中的调用顺序,以及出现继承的时候的调用过程
---------------------------------------------------------------------------------------------------------------------------------
load简介:
load 方法在类或者分类加载的时候调用,并且无论是否使用到这个分类,我们都会将其加载到内存中
也就是说哪怕分类重写的load方法,所有的分类方法依然会被调用
而且会先调用类的load方法,再调用分类的load方法
load方法只会在该类被加载到内存的时候调用一次
优先编译的类的load方法优先调用
load方法可以继承,但是一般情况下不会主动调用
---------------------------------------------------------------------------------------------------------------------------------
initialize简介:
initialize方法会在类第一次接收到消息的时候调用
且先调用父类的initialize,再调用子类的initialize
和load的区别在于initialize是通过objc_send调用的,而load是直接找到对应的方法,故存在以下特点,如果子类没有实现initialize,那么就会调用父类的initialize,如果分类实现了initialize,那么就会调用分类的initialize
category能否添加成员变量,如果可以,应该如何添加
分类可以添加属性,但是只会生产set和get的声明,而不会生成对应的实现(相当于只是进行了一个声明),所以不能直接给category添加成员变量
可以使用全局变量,字典进行模拟添加
最优解:可以使用关联对象间接添加
---------------------------------------------------------------------------------------------------------------------------------