返回

深入浅出iOS底层 —— 类的加载(下)

IOS

前言

在前两篇文章中,我们分析了类的加载过程。但在类的加载过程中,不仅仅是类本身的加载,还有分类、类的扩展等的加载。下面我们就来分析一下,分类和类的扩展是怎么加载的。

一、CPP文件分析

1. 分类

首先我们将.m文件中的分类声明复制到.h文件中,然后编译.m文件,此时.h文件中的分类声明会被编译器忽略,因为分类的实现已经包含在.m文件中。编译完成后,我们可以看到.o文件中包含了分类的实现代码。

// MyClass.h
@interface MyClass : NSObject

@end

// MyClass.m
#import "MyClass.h"

@implementation MyClass

- (void)method {
  NSLog(@"This is a method in MyClass.");
}

@end

// Category.h
@interface MyClass (Category)

- (void)categoryMethod;

@end

// Category.m
#import "Category.h"

@implementation MyClass (Category)

- (void)categoryMethod {
  NSLog(@"This is a method in Category.");
}

@end

编译后的.o文件内容如下:

// MyClass.o
...
// MyClass的实现代码
...
// Category的实现代码
...

由此可见,分类的实现代码与类本身的实现代码是放在同一个.o文件中的。

2. 类扩展

类扩展的实现代码与分类的实现代码类似,都是放在同一个.o文件中。但是,类扩展的实现代码与类本身的实现代码是分开编译的。也就是说,类扩展的实现代码不会影响类本身的实现代码。

// MyClass.h
@interface MyClass : NSObject

@end

// MyClass.m
#import "MyClass.h"

@implementation MyClass

- (void)method {
  NSLog(@"This is a method in MyClass.");
}

@end

// Extension.h
@interface MyClass (Extension)

- (void)extensionMethod;

@end

// Extension.m
#import "Extension.h"

@implementation MyClass (Extension)

- (void)extensionMethod {
  NSLog(@"This is a method in Extension.");
}

@end

编译后的.o文件内容如下:

// MyClass.o
// MyClass的实现代码

// Extension.o
// Extension的实现代码

二、运行时分析

1. 分类

分类的加载过程与类的加载过程类似。当一个分类被加载时,首先会创建一个新的类对象,然后将分类的实现代码添加到这个类对象中。这个新的类对象被称为分类类对象。分类类对象的名称与分类的名称相同,但是它的前缀是“_”。例如,分类MyClass (Category)的分类类对象名称为_MyClass_Category

分类类对象被创建后,它会被添加到类的元类对象中。类的元类对象是一个特殊的类对象,它包含了类的信息,例如类的名称、类的父类、类的属性、类的