一、前言90%开发者都会混淆的两个概念在 iOS 开发日常工作中Category分类和Extension扩展是两个出镜率极高的语法特性。但绝大多数开发者都存在认知误区认为「分类和扩展是同一个东西只是OC和Swift叫法不同」分不清什么时候用Category什么时候用Extension乱用Extension私有扩展、导致代码冲突、属性覆盖、编译报错不懂底层原理线上出现方法覆盖、执行顺序错乱疑难bug其实二者底层机制、使用权限、编译逻辑、适用场景完全不同。一句话前置总结Category 是 OC 动态编程特性主打「动态新增方法、解耦业务、批量增强类能力」Extension 是 Swift 静态语法特性主打「补全协议、拆分代码、模块化规整」本文从零拆解底层原理、核心区别、代码实战、落地规范、高频坑点彻底终结混淆认知。二、基础定义彻底分清两者归属1. Category分类专属Objective-C特性是 Runtime 动态机制的经典实现。可以在不修改原类源码、不继承、不创建子类的前提下动态为已有类系统类/自定义类新增方法。文件后缀.m / .h2. Extension扩展主要用于Swift是静态编译语法无Runtime动态特性。作用是对已有类、结构体、枚举进行静态代码补充、协议补全、代码拆分。Swift 中无 Category 概念所有类增强统一用 Extension。重要纠正OC 也有 Extension类扩展/匿名分类但几乎不用日常口语中 OC 说的「扩展」全部指 CategorySwift 全部指 Extension。三、核心本质差异底层原理级这是全文最核心内容看懂底层就不会用错场景。对比维度CategoryOC分类ExtensionSwift扩展语言归属Objective-C 专属动态特性Swift 专属静态语法特性执行机制Runtime 动态加载运行时合并方法编译期静态合并无运行时行为能否新增属性只能通过Runtime关联对象间接新增无ivar可直接新增计算属性不能存存储属性能否重写方法可以重写原类方法高危会覆盖绝对不能重写原有方法编译报错多分类优先级多个分类重写同一方法最后编译的分类覆盖前者不支持重写无覆盖逻辑协议支持可实现协议但不推荐主打协议扩展Swift模块化核心代码拆分能力弱主要用于方法增强极强按业务、协议、功能拆分代码四、OC Category 完整实战代码场景1. 基础用法系统类能力增强业务场景项目高频场景给 NSString、UIButton、UIImage 新增通用业务方法不侵入系统源码。NSStringValid.h#import Foundation/Foundation.h interface NSString (Valid) // 校验手机号合法性 - (BOOL)isValidPhoneNumber; // 校验邮箱合法性 - (BOOL)isValidEmail; endNSStringValid.m#import NSStringValid.h implementation NSString (Valid) - (BOOL)isValidPhoneNumber { if (self.length ! 11) return NO; NSString *regex ^1[3-9]\\d{9}$; NSPredicate *pred [NSPredicate predicateWithFormat:SELF MATCHES %, regex]; return [pred evaluateWithObject:self]; } - (BOOL)isValidEmail { NSString *regex [A-Z0-9a-z._%-][A-Za-z0-9.-]\\.[A-Za-z]{2,4}; NSPredicate *pred [NSPredicate predicateWithFormat:SELF MATCHES %, regex]; return [pred evaluateWithObject:self]; } end2. Category 新增属性关联对象实战Category 无法直接生成成员变量只能通过 Runtime 关联对象实现属性存储。#import UIKit/UIKit.h interface UIButton (Ext) property (nonatomic, copy) NSString *btnTag; end #import UIButtonExt.h #import objc/runtime.h implementation UIButton (Ext) - (void)setBtnTag:(NSString *)btnTag { objc_setAssociatedObject(self, selector(btnTag), btnTag, OBJC_ASSOCIATION_COPY_NONATOMIC); } - (NSString *)btnTag { return objc_getAssociatedObject(self, _cmd); } end3. Category 核心落地场景OC项目规范系统类工具增强字符串校验、日期格式化、图片处理、按钮点击防重复业务解耦将独立业务逻辑抽离分类瘦身主类全局统一UI样式统一按钮、Label、View样式构建方法埋点、统计通用方法统一页面点击、曝光埋点4. Category 高危坑点必看禁止重写系统原有方法如重写[UIButton init]会全局污染引发诡异bug多个分类新增同名方法后编译覆盖先编译方法执行不可控关联对象不支持 KVO、不参与归档不能当正式属性重度使用分类中不要写复杂初始化逻辑容易引发加载时序问题五、Swift Extension 完整实战代码场景Swift Extension 是工程化核心工具比 OC Category 更规范、更安全、能力更强。1. 基础能力扩展import UIKit extension String { // 手机号校验 func isValidPhone() - Bool { guard count 11 else { return false } let regex ^1[3-9]\\d{9}$ return NSPredicate(format: SELF MATCHES %, regex).evaluate(with: self) } } extension UIButton { // 快速创建按钮 static func create(title: String, color: UIColor) - UIButton { let btn UIButton(type: .custom) btn.setTitle(title, for: .normal) btn.setTitleColor(color, for: .normal) return btn } }2. Extension 计算属性实战Swift Extension 支持计算属性极大简化代码无存储属性、无内存占用。extension Date { // 时间戳字符串 var timeStampStr: String { return String(format: %.0f, self.timeIntervalSince1970) } // 格式化日期字符串 var ymdStr: String { let formatter DateFormatter() formatter.dateFormat yyyy-MM-dd return formatter.string(from: self) } }3. 高阶用法协议扩展Swift 核心精髓Category 做不到Extension 专属高阶能力协议默认实现统一全局能力。// 定义协议 protocol ViewLoadable { func setupUI() func setupConstraint() } // 协议默认实现所有遵守的类自动拥有能力 extension ViewLoadable where Self: UIView { func setupUI() { backgroundColor .white layer.cornerRadius 8 layer.masksToBounds true } func setupConstraint() {} } // 直接遵守无需重复实现 class CustomView: UIView, ViewLoadable { override init(frame: CGRect) { super.init(frame: frame) setupUI() } required init?(coder: NSCoder) { fatalError(init(coder:) has not been implemented) } }4. Extension 核心落地场景代码模块化拆分一个大VC用多个Extension拆分生命周期、UI、网络、点击事件协议默认实现统一组件样式、统一业务能力、消除冗余代码系统类能力增强字符串、日期、数组、字典工具方法类型规范补充补全枚举、结构体业务方法5. Extension 核心限制避坑绝对不能重写原有方法编译直接报错从语法层面杜绝覆盖风险不能添加存储属性只能用计算属性扩展方法权限高于全局同名扩展方法会优先调用自身六、Category vs Extension 选型指南团队规范1. OC 项目只用 CategoryOC 无成熟 Extension 工程化方案所有工具扩展、类能力增强统一使用 Category遵循「一个功能一个分类」。2. Swift 项目只用 ExtensionSwift 抛弃 Category 思维统一使用 Extension利用协议扩展实现高阶复用。3. 跨语言混编规范OC 分类可以被 Swift 正常调用Swift Extension 无法被 OC 识别混编项目通用工具优先用 OC Category 保证双向兼容七、高频面试题易错点总结1. 为什么 Category 不能加属性类的成员变量内存结构在编译期已经确定Category 是运行时动态追加方法无法修改原有内存布局只能通过关联对象间接存储数据。2. Category 多个同名方法谁生效工程编译顺序靠后分类会覆盖靠前分类方法执行结果不可控业务中绝对禁止同名方法。3. Extension 和 Category 最大区别Category 是 Runtime 动态行为可覆盖方法、动态加载Extension 是静态编译行为安全、规范、支持协议扩展无动态风险。八、全文总结1.OC Category动态、灵活、有风险主打系统类增强、工具方法封装需规避方法覆盖、关联对象滥用问题。2.Swift Extension静态、安全、规范主打代码拆分、协议默认实现、工程化治理是Swift项目模块化核心手段。
iOS 深挖 Category 与 Extension 本质区别
一、前言90%开发者都会混淆的两个概念在 iOS 开发日常工作中Category分类和Extension扩展是两个出镜率极高的语法特性。但绝大多数开发者都存在认知误区认为「分类和扩展是同一个东西只是OC和Swift叫法不同」分不清什么时候用Category什么时候用Extension乱用Extension私有扩展、导致代码冲突、属性覆盖、编译报错不懂底层原理线上出现方法覆盖、执行顺序错乱疑难bug其实二者底层机制、使用权限、编译逻辑、适用场景完全不同。一句话前置总结Category 是 OC 动态编程特性主打「动态新增方法、解耦业务、批量增强类能力」Extension 是 Swift 静态语法特性主打「补全协议、拆分代码、模块化规整」本文从零拆解底层原理、核心区别、代码实战、落地规范、高频坑点彻底终结混淆认知。二、基础定义彻底分清两者归属1. Category分类专属Objective-C特性是 Runtime 动态机制的经典实现。可以在不修改原类源码、不继承、不创建子类的前提下动态为已有类系统类/自定义类新增方法。文件后缀.m / .h2. Extension扩展主要用于Swift是静态编译语法无Runtime动态特性。作用是对已有类、结构体、枚举进行静态代码补充、协议补全、代码拆分。Swift 中无 Category 概念所有类增强统一用 Extension。重要纠正OC 也有 Extension类扩展/匿名分类但几乎不用日常口语中 OC 说的「扩展」全部指 CategorySwift 全部指 Extension。三、核心本质差异底层原理级这是全文最核心内容看懂底层就不会用错场景。对比维度CategoryOC分类ExtensionSwift扩展语言归属Objective-C 专属动态特性Swift 专属静态语法特性执行机制Runtime 动态加载运行时合并方法编译期静态合并无运行时行为能否新增属性只能通过Runtime关联对象间接新增无ivar可直接新增计算属性不能存存储属性能否重写方法可以重写原类方法高危会覆盖绝对不能重写原有方法编译报错多分类优先级多个分类重写同一方法最后编译的分类覆盖前者不支持重写无覆盖逻辑协议支持可实现协议但不推荐主打协议扩展Swift模块化核心代码拆分能力弱主要用于方法增强极强按业务、协议、功能拆分代码四、OC Category 完整实战代码场景1. 基础用法系统类能力增强业务场景项目高频场景给 NSString、UIButton、UIImage 新增通用业务方法不侵入系统源码。NSStringValid.h#import Foundation/Foundation.h interface NSString (Valid) // 校验手机号合法性 - (BOOL)isValidPhoneNumber; // 校验邮箱合法性 - (BOOL)isValidEmail; endNSStringValid.m#import NSStringValid.h implementation NSString (Valid) - (BOOL)isValidPhoneNumber { if (self.length ! 11) return NO; NSString *regex ^1[3-9]\\d{9}$; NSPredicate *pred [NSPredicate predicateWithFormat:SELF MATCHES %, regex]; return [pred evaluateWithObject:self]; } - (BOOL)isValidEmail { NSString *regex [A-Z0-9a-z._%-][A-Za-z0-9.-]\\.[A-Za-z]{2,4}; NSPredicate *pred [NSPredicate predicateWithFormat:SELF MATCHES %, regex]; return [pred evaluateWithObject:self]; } end2. Category 新增属性关联对象实战Category 无法直接生成成员变量只能通过 Runtime 关联对象实现属性存储。#import UIKit/UIKit.h interface UIButton (Ext) property (nonatomic, copy) NSString *btnTag; end #import UIButtonExt.h #import objc/runtime.h implementation UIButton (Ext) - (void)setBtnTag:(NSString *)btnTag { objc_setAssociatedObject(self, selector(btnTag), btnTag, OBJC_ASSOCIATION_COPY_NONATOMIC); } - (NSString *)btnTag { return objc_getAssociatedObject(self, _cmd); } end3. Category 核心落地场景OC项目规范系统类工具增强字符串校验、日期格式化、图片处理、按钮点击防重复业务解耦将独立业务逻辑抽离分类瘦身主类全局统一UI样式统一按钮、Label、View样式构建方法埋点、统计通用方法统一页面点击、曝光埋点4. Category 高危坑点必看禁止重写系统原有方法如重写[UIButton init]会全局污染引发诡异bug多个分类新增同名方法后编译覆盖先编译方法执行不可控关联对象不支持 KVO、不参与归档不能当正式属性重度使用分类中不要写复杂初始化逻辑容易引发加载时序问题五、Swift Extension 完整实战代码场景Swift Extension 是工程化核心工具比 OC Category 更规范、更安全、能力更强。1. 基础能力扩展import UIKit extension String { // 手机号校验 func isValidPhone() - Bool { guard count 11 else { return false } let regex ^1[3-9]\\d{9}$ return NSPredicate(format: SELF MATCHES %, regex).evaluate(with: self) } } extension UIButton { // 快速创建按钮 static func create(title: String, color: UIColor) - UIButton { let btn UIButton(type: .custom) btn.setTitle(title, for: .normal) btn.setTitleColor(color, for: .normal) return btn } }2. Extension 计算属性实战Swift Extension 支持计算属性极大简化代码无存储属性、无内存占用。extension Date { // 时间戳字符串 var timeStampStr: String { return String(format: %.0f, self.timeIntervalSince1970) } // 格式化日期字符串 var ymdStr: String { let formatter DateFormatter() formatter.dateFormat yyyy-MM-dd return formatter.string(from: self) } }3. 高阶用法协议扩展Swift 核心精髓Category 做不到Extension 专属高阶能力协议默认实现统一全局能力。// 定义协议 protocol ViewLoadable { func setupUI() func setupConstraint() } // 协议默认实现所有遵守的类自动拥有能力 extension ViewLoadable where Self: UIView { func setupUI() { backgroundColor .white layer.cornerRadius 8 layer.masksToBounds true } func setupConstraint() {} } // 直接遵守无需重复实现 class CustomView: UIView, ViewLoadable { override init(frame: CGRect) { super.init(frame: frame) setupUI() } required init?(coder: NSCoder) { fatalError(init(coder:) has not been implemented) } }4. Extension 核心落地场景代码模块化拆分一个大VC用多个Extension拆分生命周期、UI、网络、点击事件协议默认实现统一组件样式、统一业务能力、消除冗余代码系统类能力增强字符串、日期、数组、字典工具方法类型规范补充补全枚举、结构体业务方法5. Extension 核心限制避坑绝对不能重写原有方法编译直接报错从语法层面杜绝覆盖风险不能添加存储属性只能用计算属性扩展方法权限高于全局同名扩展方法会优先调用自身六、Category vs Extension 选型指南团队规范1. OC 项目只用 CategoryOC 无成熟 Extension 工程化方案所有工具扩展、类能力增强统一使用 Category遵循「一个功能一个分类」。2. Swift 项目只用 ExtensionSwift 抛弃 Category 思维统一使用 Extension利用协议扩展实现高阶复用。3. 跨语言混编规范OC 分类可以被 Swift 正常调用Swift Extension 无法被 OC 识别混编项目通用工具优先用 OC Category 保证双向兼容七、高频面试题易错点总结1. 为什么 Category 不能加属性类的成员变量内存结构在编译期已经确定Category 是运行时动态追加方法无法修改原有内存布局只能通过关联对象间接存储数据。2. Category 多个同名方法谁生效工程编译顺序靠后分类会覆盖靠前分类方法执行结果不可控业务中绝对禁止同名方法。3. Extension 和 Category 最大区别Category 是 Runtime 动态行为可覆盖方法、动态加载Extension 是静态编译行为安全、规范、支持协议扩展无动态风险。八、全文总结1.OC Category动态、灵活、有风险主打系统类增强、工具方法封装需规避方法覆盖、关联对象滥用问题。2.Swift Extension静态、安全、规范主打代码拆分、协议默认实现、工程化治理是Swift项目模块化核心手段。