目錄
- 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 擴展。