1、一个NSObject对象占用多少内存?
回答:
系统分配了16个字节给NSObject对象(通过malloc_size
函数获得)(因为内存对齐,必须是16的倍数)
但NSObject对象内部只有一个isa指针,只使用了8个字节的空间(64bit环境下,可以通过class_getInstanceSize
函数获得)
2、对象的isa指针指向哪里?
回答:
instance对象的isa指针指向class对象
class对象的isa指针指向meta-class对象
meta-class对象的isa指针指向基类的meta-class对象
3、OC的类信息存放在哪里?
回答:
- 对象方法、属性、成员变量、协议信息,存放在class对象中
- 类方法,存放在meta-class对象中
- 成员变量的具体值,存放在instance对象中
4、iOS用什么方式实现对一个对象的KVO?(KVO的本质是什么?)
回答:
- 利用RuntimeAPI生成一个子类NSKVOXXXNotifying,并且让instance对象的isa指针指向这个全新的子类
- 当修改instance对象的属性时,会调用Foundation框架中的_NSSetXXXValueAndNotify函数(重写了setter方法):
- willChangeValueForKey:
- 父类原来的setter方法
- didChangeValueForKey:
- 内部会触发监听器(Observer)的监听方法(observeValueForKeyPath:ofObject:change:context)
5、如何手动触发KVO?
回答:
手动去调用willChangeValueForKey:和didChangeValueForKey:的方法
6、直接修改成员变量会触发KVO吗?
回答:
不会,因为修改成员变量并不会调用setter方法
7、通过KVC修改属性会触发KVO吗?
回答:
会触发KVO,通过KVC修改相当于手动调用了willChangeValueForKey:和didChangeValueForKey:
8、KVC的赋值和取值的过程是怎样的?原理是什么?
回答:
赋值:
取值:
9、Category的使用场合是什么?
回答:
- 类包含了很多个方法实现,而这些方法需要不同团队的成员来实现
- 当你在使用基础类库中的类时,你不想继承这些类,而只是想添加一些方法的时候
10、Category的实现原理
回答:
- Category编译之后的底层结构是
struct category_t
,里面存储着分类的对象方法、类方法、属性、协议信息 - 程序运行的时候,runtime会将Category的数据,合并到类信息中(类对象、元类对象中)
11、Category和Class Extension的区别是什么?
回答:
- Class Extension是在程序编译的时候,它的数据就已经包含在类信息中了
- Category在底层是以结构体的形式存在,在程序运行的时候,才会将数据合并到类信息中
12、Category中有load方法吗?load方法是什么时候调用的?load方法能继承吗?
回答:
- 有
load
方法 load
方法在runtime
加载类、分类的时候调用,而且只调用一次load
方法可以继承,但是一般情况下不会主动去调用load
方法,都是让系统自动调用
13、load、initialize方法的区别是什么?它们在category中的调用顺序?以及出现继承时它们之间的调用过程?
回答:
load方法
load
方法会在Runtime
加载类、分类的时候调用每个类、分类的
load
,在程序运行的过程中只调用一次调用顺序:
先调用类的
load
按照编译的先后顺序调用(先编译,先调用)
调用子类的
load
之前会先调用父类的load
再调用分类的
load
- 按照编译先后顺序调用(先编译,先调用)
load
方法系统调用和主动调用的区别- 系统调用
load
是直接找到类或分类中的方法的内存地址直接调用 - 主动调用
load
是通过消息机制来发送消息的,会在对应的消息列表里按顺序遍历一层层查找,找到就调用
- 系统调用
initialize方法
initialize
方法会在类第一次接收到消息时调用调用顺序:
- 先调用父类的
initialize
,再调用子类的initialize
,每个类只会初始化1次(如果子类没有实现initialize
方法,会调用父类的initialize
方法,所以父类的initialize
方法可能会调用多次)
- 先调用父类的
initialize
的调用是通过消息机制来发送消息的
14、Category能否添加成员变量?如果可以,如何给Category添加成员变量?
回答:
不能直接给Category
添加成员变量,但是可以简介实现Category
有成员变量的效果——关联对象
15、Block的原理是怎样的?Block的本质是什么?
回答:
其本质就是封装了函数调用以及调用环境的OC对象
16、__block的作用是什么?有什么使用注意点?
回答:
可以将修饰的对象包装成一个对象,解决在block
内部无法修改外部变量的问题。
__block
内部会进行内存管理,在MRC
环境下不会对对象进行强引用。
17、看下面代码,分别输出的值是什么?
1 | int a = 10; |
回答:
输出结果为:age=10,height=20,a=20,b=20
age
是自动变量,是值传递
height
表示的是指针传递,block
获取的是该变量的地址
而a/b
都是全局变量,block
不会捕获,需要时直接拿取当前最新的值就可以了
1 | int a = 10; |
18、看下面代码,block内部会不会捕获self?
1 | @interface Person : NSObject |
回答:
会捕获,因为self
本质上也是一个局部变量,block
内部会生成一个变量来保存Person对象
的地址
1 | struct __Person__test_block_impl_0 { |
19、Block的属性词为什么是Copy?使用Block有哪些注意事项?
回答:
block
如果没有进行copy
操作,就不会放在堆上。放到堆上的主要目的是方便我们来控制它的生命周期,可以更有效的进行内存管理。
注意事项:注意不要产生循环引用