IOS面试题——OC分类Category原理(3)

一 面试题汇总

  1. Category底层结构是怎么样的
  2. 为什么说不能添加属性?
  3. Category加载过程?同名方法如何处理?
  4. load方法和initialize的区别?
  5. 怎么添加成员变量?
  6. 关联对象是如何存储的?
  7. 分类和扩展的区别是什么?

二 面试题解答(仅供参考)

2.1 Category底层结构是怎么样的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Category的底层结构包括以下部分:

1-方法列表(Method List):
Category中添加的方法都会被组织成一个方法列表。
这个列表包含了方法的名称、参数类型以及实现的指针。

2-元类对象(Meta Class)的修改:
如果Category中添加了类方法,那么这些类方法会被添加到元类对象(Meta Class)中,
这样所有该类的实例对象和类对象都可以访问这些类方法。

3-Category的元数据(Metadata):
Category本身也会有一些元数据,这些元数据包括Category的名称、被扩展的原始类的名称等信息。

总的来说,Category的底层结构是一个与原始类相似的结构,但它包含了额外的方法列表和元数据,
使得这些额外的方法能够在运行时被正确地加载和调用。

2.2 为什么说不能添加属性?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
在 Objective-C 中,使用 Category 无法直接添加属性的主要原因是
由于 Objective-C 编译器的限制以及运行时系统的限制。

1-编译器限制:
在 Objective-C 中,Category 可以添加方法,但不能添加实例变量。
属性(Property)通常需要与实例变量相关联,
因为属性的本质是对实例变量的访问器(getter 和 setter)的封装。
由于 Category 无法添加实例变量,因此也就无法直接添加属性。

2-运行时系统限制:
Objective-C 的运行时系统负责在运行时管理类和对象。
当一个类被加载到运行时系统中时,它的实例对象的内存布局已经确定。
因此,如果在运行时添加了新的实例变量,
那么原来已经分配的内存空间就无法容纳这些新的实例变量,这可能会导致内存布局的不一致和潜在的错误。

2.3 Category加载过程?同名方法如何处理?

1
2
3
4
5
6
7
8
9
在 Objective-C 中,Category 的加载过程是在运行时进行的,而不是在编译时。
当你的应用程序启动时,Objective-C 运行时系统会加载所有的类及其相关的 Category。

加载 Category 的过程大致如下:

1-编译阶段:在编译时,Category 的信息会被编译到一个独立的目标文件中。
2-链接阶段:在链接时,这些 Category 的目标文件会被与应用程序的可执行文件链接在一起。
3-运行时加载:在应用程序启动时,Objective-C 运行时系统会扫描并加载所有的类及其相关的 Category。
这个过程是动态的,所以即使 Category 的目标文件是在链接时添加的,它们也会被正确地加载。

2.4 load方法和initialize的区别?

1
2
3
4
5
6
7
8
9
10
11
+load 方法在类被加载到运行时系统时调用,
而 +initialize 方法在类或其子类的第一个消息被发送到该类或子类时调用。

+load 方法是在程序启动时自动调用的,
而 +initialize 方法是在类或其子类的第一次收到消息时调用的。

+load 方法的调用顺序是根据类的继承关系和加载顺序决定的,
而 +initialize 方法的调用顺序是根据类的继承关系和消息发送顺序决定的。

+load 方法一般用于执行一些全局初始化的操作,
而 +initialize 方法一般用于执行类的实例变量的初始化操作。

2.5 怎么添加成员变量?

1
2
3
在 Objective-C 中,成员变量(Instance Variables)一般是通过在类的接口(@interface)中声明来添加的。
但是,在现代 Objective-C 中,推荐使用属性(Properties)来替代直接操作成员变量。
不过,如果你确实需要直接操作成员变量,可以在类的接口或实现(@implementation)中添加

2.6 关联对象是如何存储的?

1
2
关联对象的存储是通过 Objective-C 运行时系统中的关联引用表(Associated References Table)来实现的。
这个表是一个全局的数据结构,用于跟踪对象和关联对象之间的关系

2.7 分类和扩展的区别是什么?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
在 Objective-C 中,分类(Category)和扩展(Extension)都是用来在现有类中添加额外功能的机制,但它们有一些关键的区别:

1-可见性和命名空间:

1.1-分类(Category): 分类允许你在不修改原始类声明的情况下向现有类添加方法。
这些方法在使用时与原始类中的方法没有区别,因此分类可以用来给类添加新的功能,
也可以用来将类的相关方法进行分组。
1.2-扩展(Extension): 扩展是一种匿名的分类,它允许你在类的实现文件(.m 文件)中声明私有的实例变量和私有方法。
扩展的主要目的是提供一种方式来隐藏类的私有实现细节,它们通常被用于声明私有的方法或者只在类的实现中使用的方法。

2-作用域:

2.1-分类(Category): 分类的方法可以被其他类调用,因此它们的作用域是全局的。
你可以在任何文件中导入分类的头文件,并且调用其中的方法。
2.2-扩展(Extension): 扩展中声明的方法和实例变量只能在类的实现文件中被访问,因此它们的作用域是局部的。
扩展一般会被定义在类的实现文件中,并且不会暴露给其他类。

3-实例变量:

3.1-分类(Category): 分类不能添加实例变量。你只能添加方法,不能添加成员变量。
3.2-扩展(Extension): 扩展可以添加实例变量,但是只能在类的实现文件中添加,并且只能添加在类的扩展声明中,而不能添加在分类中。

综上所述,分类和扩展都是用来扩展现有类的功能,但是它们的作用和用法有所不同。
分类主要用于向现有类添加方法,而扩展主要用于隐藏类的私有实现细节和声明私有方法

三 参考

  • 简书—OC分类Category原理