在 Objective-C 中,分类 (Category) 和 协议 (Protocol) 是实现代码解耦、扩展功能和组件化开发的核心工具。
一、 分类 (Category)
分类 允许你在不修改原始类代码、不使用继承的情况下,动态地为现有的类添加新方法。
1. 核心作用
- 扩展系统类 :给
NSString,NSArray等添加自定义工具方法。 - 分解大型类 :将一个庞大的
.m文件按功能拆分成多个小文件(如User+Login.m,User+Profile.m)。
2. 代码案例:给 NSString 增加一个校验邮箱的功能
NSString+Email.h (声明)
objectivec
#import <Foundation/Foundation.h>
@interface NSString (Email)
// 声明一个新方法
- (BOOL)isEmailFormat;
@end
NSString+Email.m (实现)
objectivec
#import "NSString+Email.h"
@implementation NSString (Email)
- (BOOL)isEmailFormat {
NSString *emailRegex = @"[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}";
NSPredicate *emailTest = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", emailRegex];
return [emailTest evaluateWithObject:self];
}
@end
使用方法:
objectivec
#import "NSString+Email.h"
NSString *myMail = @"test@example.com";
if ([myMail isEmailFormat]) {
NSLog(@"这是一个有效的邮箱");
}
3. 注意事项
- 只能添加方法,不能添加成员变量(可以通过"关联对象"实现,但属于进阶内容)。
- 方法覆盖 :如果分类中的方法名与原类重复,分类的方法会"覆盖"原类。建议分类方法名加上前缀(如
my_isEmailFormat)。
二、 协议 (Protocol)
协议 定义了一套方法列表,但不负责实现。任何类都可以声明"遵守"这个协议并实现其中的方法。它类似于 Java 或 C# 中的 Interface(接口)。
1. 核心关键字
@required:必须实现的方法(默认)。@optional:可选实现的方法。
2. 代码案例:定义一个"管家"协议
HouseKeeperProtocol.h
objectivec
#import <Foundation/Foundation.h>
@protocol HouseKeeperProtocol <NSObject>
@required
- (void)cleanRoom; // 必须打扫房间
@optional
- (void)cookDinner; // 可以选择是否做饭
@end
Person.h (类声明遵守协议)
objectivec
#import "HouseKeeperProtocol.h"
// 在类名后用 <> 表示遵守协议
@interface Person : NSObject <HouseKeeperProtocol>
@end
Person.m (实现协议方法)
objectivec
@implementation Person
- (void)cleanRoom {
NSLog(@"正在用吸尘器打扫...");
}
// cookDinner 是可选的,可以不写
@end
三、 协议的高级用法:委托模式 (Delegate)
这是协议在 iOS 开发中最常用的场景(如 TableView 的点击事件)。
objectivec
// 1. 定义协议
@protocol DownloadDelegate <NSObject>
- (void)downloadDidFinish:(NSString *)filePath;
@end
// 2. 在下载器类中定义 delegate 属性
@interface Downloader : NSObject
@property (nonatomic, weak) id<DownloadDelegate> delegate;
- (void)start;
@end
@implementation Downloader
- (void)start {
NSLog(@"下载中...");
// 3. 通知代理对象
if ([self.delegate respondsToSelector:@selector(downloadDidFinish:)]) {
[self.delegate downloadDidFinish:@"/path/to/file"];
}
}
@end
四、 分类 vs 协议:怎么选?
| 特性 | 分类 (Category) | 协议 (Protocol) |
|---|---|---|
| 主要目的 | 扩展:给现有类增加功能 | 规范:定义一套行为准则 |
| 方法实现 | 必须在分类的 .m 中实现 |
协议本身不实现,由遵守它的类实现 |
| 状态存储 | 不允许添加成员变量 | 不涉及变量,只涉及方法 |
| 使用场景 | 比如想给所有 UIButton 加一个抖动动画 |
比如定义"凡是能飞的物体(鸟、飞机)都要有 fly 方法" |
总结
- 如果你想让某个现有的类"更强大 ",用 Category。
- 如果你想让不同的类"遵守同一种约定 "或者实现"回调通知 ",用 Protocol。