【iOS Sharing】【4】类相关

本文最后更新于:2021年12月22日 上午

【iOS笔记】系列目录


目录

1、请用一句话概述分类的概念,并阐述分类的优点。

2、多个同宿主分类中的都重写了一个同名方法,哪个分类的同名方法会生效?为什么?

3. Category、 Extension和继承的区别?

4. isKindOfClass、isMemberOfClass作用分别是什么?

5. +load 和 +initialize 的区别是什么?


1、请用一句话概述分类的概念,并阐述分类的优点。

答:

概述:Objective-C中的分类是修饰模式的一种具体实现,主要作用是在不改变原有类的基础上,动态的为类扩展功能(添加方法)。

分类的优点

  • 声明私有方法
  • 分解庞大的类文件
  • 将Framework私有方法公开化
  • 模拟多继承

2、多个同宿主分类中的都重写了一个同名方法,哪个分类的同名方法会生效?为什么?

答:

运行时在处理分类时会倒序遍历分类数组,最先访问最后编译的类,最后编译的类的同名方法最终生效。

下面我们来看看源码解析:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
int mcount = 0; // 记录方法的数量
int propcount = 0; // 记录属性的数量
int protocount = 0; // 记录协议的数量
int i = cats->count; // 获取分类个数
bool fromBundle = NO; // 记录是否是从 bundle 中取的

while (i--) { // 从后往前遍历,保证先取最后编译的类
auto&;
entry = cats->list[i]; // 分类,locstamped_category_t 类型

// 取出分类中的方法列表;如果是元类,取得的是类方法列表;否则取得的是实例方法列表
method_list_t *mlist = entry.cat->methodsForMeta(isMeta);
if (mlist) {
mlists[mcount++] = mlist; // 将方法列表放入 mlists 方法列表数组中
fromBundle |= entry.hi->isBundle(); // 分类的头部信息中存储了是否是 bundle,将其记住
}

// 取出分类中的属性列表,如果是元类,取得是nil
property_list_t *proplist = entry.cat->propertiesForMeta(isMeta);
if (proplist) {
proplists[propcount++] = proplist; // 将属性列表放入 proplists 属性列表数组中
}

// 取出分类中遵循的协议列表
protocol_list_t *protolist = entry.cat->protocols;
if (protolist) {
protolists[protocount++] = protolist; // 将协议列表放入 protolists 协议列表数组中
}
}

3. Category、 Extension和继承的区别?

  • Category有名字,Extension没有名字,是一种特殊的Category
  • Category只能扩展方法(属性仅仅是声明,并没真正实现),Extension可以扩展属性、成员变量和方法。
  • 继承可以增加,修改或者删除方法,并且可以增加属性。

4. isKindOfClass、isMemberOfClass作用分别是什么?

  • isKindOfClass:作用是某个对象属于某个类型或者继承自某类型。
  • isMemberOfClass:某个对象确切属于某个类型。
1
2
3
4
5
6
7
8
9
10
11
12
//Dog继承自Animal
Animal *a = [Animal new];
Dog *d = [Dog new];

NSLog(@"%d",[a isKindOfClass:[Animal class]]); //1
NSLog(@"%d",[a isMemberOfClass:[Animal class]]); //1

NSLog(@"%d",[d isKindOfClass:[Animal class]]); //1
NSLog(@"%d",[d isMemberOfClass:[Animal class]]); //0

NSLog(@"%d",[d isKindOfClass:[Dog class]]); //1
NSLog(@"%d",[d isMemberOfClass:[Dog class]]); //1

Warning:
不要对NSArray、NSString等Apple实现的类进行isMemberOfClass操作,得出的结果是false

1
2
NSString *s = @"";
NSLog(@"%d",[s isMemberOfClass:[NSString class]]); //0

Apple使用类簇的方式实现的这些类,所以s不是NSString类的实例。

5. +load 和 +initialize 的区别是什么?

+(void)load;

+load 方法是当类或分类被添加到 Objective-C runtime 时被调用的,实现这个方法可以让我们在类加载的时候执行一些类相关的行为。子类的 +load 方法会在它的所有父类的 +load 方法之后执行,而分类的 +load 方法会在它的主类的 +load 方法之后执行。但是不同的类之间的 +load 方法的调用顺序是不确定的。

+(void)initialize;

+initialize 方法是在类或它的子类收到第一条消息之前被调用的,这里所指的消息包括实例方法和类方法的调用。也就是说 +initialize 方法是以懒加载的方式被调用的,如果程序一直没有给某个类或它的子类发送消息,那么这个类的 +initialize 方法是永远不会被调用的。


联系方式

邮箱: adrenine@163.com