目录
- 1. 语言环境
- 2. 主要目的
- 3. 核心能力对比
- 4. 关键差异详解
- 4.1. 属性支持
- 4.2. Swift 扩展
- 4.3. 初始化器
- 4.4. 方法冲突与覆盖
- 4.5. 关联类型与泛型
- 5. 设计哲学
- 6. 总结表
在 Objective-C 和 Swift 中,分类(Category)和扩展(Extension)都是为现有类添加新功能的方式,但它们在实现、能力和特性上有显著区别:
1. 语言环境
- OC分类:用于Objective-C语言。
- Swift扩展:用于Swift语言,用于 Swift 中的类、结构体、枚举或协议。
2. 主要目的
- OC分类:主要目的是为已有的类添加方法(包括实例方法和类方法),也可以添加属性(但属性不会自动生成实例变量,需要借助关联对象)。
- Swift扩展:可以添加新的计算属性、方法(实例方法和类方法)、构造器、下标、嵌套类型,还可以使已有类型遵循某个协议。
3. 核心能力对比
功能 | Objective-C 分类 | Swift 扩展 |
---|---|---|
添加方法 | ✅ 支持 | ✅ 支持 |
添加计算属性 | ❌ 不支持(需关联对象模拟) | ✅ 支持 |
添加存储属性 | ❌ 不支持(需关联对象模拟) | ❌ 不支持 |
添加初始化器 | ⚠️ 可为类添加新初始化器(需调用 self = [super init] ) | ✅ 可为结构体/枚举添加;类仅支持便利初始化器 |
添加嵌套类型 | ❌ 不支持 | ✅ 支持(嵌套类/结构体/枚举) |
遵守协议 | ✅ 支持 | ✅ 支持 |
覆盖现有方法 | ⚠️ 支持(但易冲突,不推荐) | ❌ 编译错误(不允许覆盖) |
4. 关键差异详解
4.1. 属性支持
Objective-C 分类:
不能直接添加存储属性。需用 @property
+ 关联对象(objc_setAssociatedObject
)模拟,但本质是全局字典而非真实属性。
// 分类中模拟“存储属性”
@property (nonatomic, strong) NSString *tempProperty;
- (void)setTempProperty:(NSString *)value {objc_setAssociatedObject(self, @"key", value, OBJC_ASSOCIATION_RETAIN);
}
- (NSString *)tempProperty {return objc_getAssociatedObject(self, @"key");
}
4.2. Swift 扩展
可直接添加计算属性,但不能添加存储属性或属性观察器(didSet
/willSet
)。
extension UIView {var screenSize: CGSize { // ✅ 计算属性return UIScreen.main.bounds.size}// ❌ 以下会编译报错// var storedProperty: Int = 0// var observedProperty: Int { didSet { ... } }
}
4.3. 初始化器
Objective-C 分类:
可为类添加新初始化器,但需手动调用 self = [super init]
,且可能破坏封装性。
@implementation NSString (MyCategory)
- (instancetype)initWithCustomFormat {self = [self initWithString:@"Custom"];return self;
}
@end
Swift 扩展:
- 值类型(结构体/枚举):可添加新初始化器(需确保所有存储属性初始化)。
- 引用类型(类):只能添加便利初始化器(
convenience init
),不能添加指定初始化器或析构器。
extension CGRect {// ✅ 值类型的初始化器init(center: CGPoint, size: CGSize) {self.init(origin: CGPoint(x: center.x - size.width/2, y: center.y - size.height/2), size: size)}
}class MyClass {}
extension MyClass {// ✅ 类的便利初始化器convenience init(custom: Int) {self.init()// 配置逻辑}// ❌ 报错:不能添加指定初始化器// init(custom: Int) { ... }
}
4.4. 方法冲突与覆盖
- Objective-C 分类:
允许覆盖原类方法(编译通过),但多个分类覆盖同一方法时,行为由加载顺序决定(最后加载的分类生效),易引发难以调试的冲突。
Swift 扩展:
严格禁止覆盖现有成员(编译错误),确保类型安全:
class MyClass {func print() { }
}
extension MyClass {func print() { } // ❌ 编译报错:Invalid redeclaration of 'print()'
}
4.5. 关联类型与泛型
Swift 扩展:
可为协议添加默认实现,支持泛型约束:
extension Collection where Element: Equatable {func contains(_ element: Element) -> Bool { ... } // 为所有元素可判等的集合添加默认方法
}
- Objective-C 分类:
无法支持泛型或协议扩展。
5. 设计哲学
- Objective-C 分类:
基于运行时的动态特性,允许方法覆盖(风险高),依赖关联对象模拟属性,灵活性高但安全性低。 - Swift 扩展:
编译时静态解析,禁止覆盖,强调类型安全,支持协议扩展和泛型,更适合构建健壮架构。
6. 总结表
特性 | Objective-C 分类 | Swift 扩展 |
---|---|---|
作用对象 | 仅 Objective-C 类 | 类、结构体、枚举、协议 |
存储属性 | ❌(需关联对象模拟) | ❌ |
计算属性 | ❌ | ✅ |
方法覆盖 | ⚠️ 允许(有风险) | ❌ 编译禁止 |
协议默认实现 | ❌ | ✅ |
泛型支持 | ❌ | ✅(通过 **where** 子句) |
安全性 | 低(运行时冲突) | 高(编译时检查) |
根据需求选择:
- 需动态添加属性/覆盖方法 → Objective-C 分类(需谨慎)。
- 需类型安全/添加计算逻辑/扩展协议 → Swift 扩展。