Class Extension(类扩展)在 Objective-C 中常被称为“匿名分类”(Anonymous Category),但其核心价值与普通分类(Category)完全不同。它的真实用途可以归纳为一句话:在保证类内存布局安全的前提下,实现“接口私有化”与“实现细节隐藏”。
以下是 Class Extension 的四大核心用途:
1. 声明私有成员变量(ivar)与属性
这是 Class Extension 最最常用的功能。
- 为什么用它: 普通分类(Category)无法添加成员变量,但 Class Extension 可以。
- 真实用途: 在
.h文件中保持接口整洁,仅公开必要的属性;而将逻辑运行所需的内部变量、私有属性隐藏在.m文件的 Extension 中。
Objective-C
// Person.h
@interface Person : NSObject
@property (nonatomic, copy, readonly) NSString *name; // 对外只读
@end
// Person.m
@interface Person () // Class Extension
@property (nonatomic, copy, readwrite) NSString *name; // 内部可读写
@property (nonatomic, strong) NSString *internalID; // 完全私有的属性
{
NSInteger _age; // 私有成员变量
}
@end
2. 修改属性的访问权限(Readonly 变 Readwrite)
这是封装逻辑中的经典套路。
- 用途: 很多时候,我们希望外界只能读取某个属性(
readonly),但类内部需要根据逻辑修改它(readwrite)。 - 底层: 通过 Class Extension 重新声明该属性,编译器会自动为该类生成 Setter 方法,而这个 Setter 方法对外部调用者是不可见的。
3. 私有方法的正式声明
虽然 Objective-C 没有严格意义上的“私有方法”(只要知道 Selector 就能调用),但 Class Extension 提供了一个编译期的约束。
- 用途: 在
.m的 Extension 中声明私有方法,可以让该方法在当前类的实现文件内获得自动补全和编译检查。 - 优势: 如果你只是直接在
@implementation里写方法而不声明,虽然能运行,但编译器在某些情况下(如方法在调用点之后定义)会报警告。
4. 遵守私有协议(Private Protocols)
当一个类需要遵循某个协议(如 UITableViewDelegate),但你并不希望外界知道这个类实现了这些协议时:
- 用途: 将协议声明放在 Class Extension 中。
- 效果: 这样可以防止外界滥用代理方法,同时也符合“接口最小化”的原则,让
.h文件只包含业务相关的定义。
Class Extension vs Category 的本质区别
为了彻底理解其用途,必须对比它们在底层处理上的差异:
| 维度 | Class Extension | Category |
|---|---|---|
| 生效时间 | 编译期(和原类编译在一起) | 运行时(启动时动态加载) |
| 添加成员变量 | 可以 | 不可以 |
| 源码要求 | 必须有原类源码 | 不需要原类源码 |
| 存在形式 | 没有独立的 .m 实现 | 有独立的 .h 和 .m |
总结:它到底解决了什么问题?
Class Extension 解决了 “封装性” 问题。它让类能够像“黑盒”一样工作:外部看到的 .h 极其简单,而内部的复杂变量、读写权限切换、私有协议全部被整齐地收纳在 .m 的 Extension 之中。