文章目录
- [一、 Delegate 模式的概念](#一、 Delegate 模式的概念)
- [二、Delegate 的实现步骤](#二、Delegate 的实现步骤)
-
- [步骤 1: 定义一个协议(Protocol)](#步骤 1: 定义一个协议(Protocol))
- [步骤 2: 在主类中添加一个 delegate 属性](#步骤 2: 在主类中添加一个 delegate 属性)
- [步骤 3: 实现协议的类遵守协议并实现方法](#步骤 3: 实现协议的类遵守协议并实现方法)
- [步骤 4: 设置 delegate](#步骤 4: 设置 delegate)
- [三、Delegate 模式的特点](#三、Delegate 模式的特点)
- [四、Delegate 模式的常见场景](#四、Delegate 模式的常见场景)
-
- [1. 视图控制器与视图组件之间的通信](#1. 视图控制器与视图组件之间的通信)
- [2. 处理用户输入事件](#2. 处理用户输入事件)
- [3. 自定义控件的回调](#3. 自定义控件的回调)
- [4. 事件的传递与回调](#4. 事件的传递与回调)
- [5. 解耦设计](#5. 解耦设计)
- [6. 常见框架与委托](#6. 常见框架与委托)
一、 Delegate 模式的概念
- 核心思想:一个对象定义协议(Protocol),让其他对象遵守协议并实现相关方法,最终将任务交给这些对象完成。
- 使用场景:实现对象之间的事件回调、数据传递 和 解耦。
二、Delegate 的实现步骤
步骤 1: 定义一个协议(Protocol)
协议中声明了需要实现的方法。
objectivec
@protocol MyDelegate <NSObject>
- (void)taskDidComplete; // 定义协议方法
@end
步骤 2: 在主类中添加一个 delegate 属性
主类通过 weak 引用委托对象,避免循环引用。
objectivec
@interface MyClass : NSObject
@property (nonatomic, weak) id<MyDelegate> delegate; // 弱引用
- (void)startTask;
@end
@implementation MyClass
- (void)startTask {
NSLog(@"Task is starting...");
// 模拟任务完成
[self.delegate taskDidComplete]; // 调用委托对象的方法
}
@end
步骤 3: 实现协议的类遵守协议并实现方法
其他类通过遵守 MyDelegate 协议来实现任务。
objectivec
@interface AnotherClass : NSObject <MyDelegate>
@end
@implementation AnotherClass
- (void)taskDidComplete {
NSLog(@"Task completed! Delegate notified.");
}
@end
步骤 4: 设置 delegate
主类通过 delegate 属性与实现类建立连接。
objectivec
int main(int argc, const char * argv[]) {
@autoreleasepool {
MyClass *myClass = [[MyClass alloc] init];
AnotherClass *anotherClass = [[AnotherClass alloc] init];
myClass.delegate = anotherClass; // 设置委托对象
[myClass startTask]; // 触发任务
}
return 0;
}
输出:
objectivec
Task is starting...
Task completed! Delegate notified.
三、Delegate 模式的特点
- 解耦:实现者(委托对象)和调用者(主类)分离,降低耦合度。
- 灵活性:不同的对象可以遵守协议,实现不同的逻辑。
- 单向通信:委托对象实现协议方法,主类通过调用这些方法实现通信。
四、Delegate 模式的常见场景
1. 视图控制器与视图组件之间的通信
在 iOS 中,视图组件(如 UITableView、UITextField)通过 Delegate 与控制器通信,传递事件和数据。
示例:UITableView 的 Delegate 和 DataSource
UITableView 的事件(例如单元格选中、滚动)通过 UITableViewDelegate 和 UITableViewDataSource 协议回调到控制器中。
objectivec
@interface ViewController () <UITableViewDelegate, UITableViewDataSource>
@property (nonatomic, strong) UITableView *tableView;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.tableView = [[UITableView alloc] initWithFrame:self.view.bounds];
self.tableView.delegate = self;
self.tableView.dataSource = self;
[self.view addSubview:self.tableView];
}
// UITableViewDataSource 方法
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 10; // 返回行数
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"cell"];
}
cell.textLabel.text = [NSString stringWithFormat:@"Row %ld", (long)indexPath.row];
return cell;
}
// UITableViewDelegate 方法
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(@"Selected row: %ld", (long)indexPath.row);
}
@end
2. 处理用户输入事件
委托模式在输入控件(如 UITextField 和 UITextView)中广泛使用,用于处理用户输入。
objectivec
@interface ViewController () <UITextFieldDelegate>
@property (nonatomic, strong) UITextField *textField;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.textField = [[UITextField alloc] initWithFrame:CGRectMake(50, 100, 200, 40)];
self.textField.borderStyle = UITextBorderStyleRoundedRect;
self.textField.delegate = self;
[self.view addSubview:self.textField];
}
// UITextFieldDelegate 方法
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
[textField resignFirstResponder]; // 隐藏键盘
return YES;
}
@end
3. 自定义控件的回调
在开发自定义控件时,可以定义一个 delegate,让外部类(通常是视图控制器)实现回调方法,处理控件的行为。
示例:自定义控件
objectivec
@protocol CustomViewDelegate <NSObject>
- (void)customViewButtonWasTapped;
@end
@interface CustomView : UIView
@property (nonatomic, weak) id<CustomViewDelegate> delegate;
@end
@implementation CustomView
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(50, 50, 100, 50)];
[button setTitle:@"Tap Me" forState:UIControlStateNormal];
[button setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
[button addTarget:self action:@selector(buttonTapped) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:button];
}
return self;
}
- (void)buttonTapped {
[self.delegate customViewButtonWasTapped];
}
@end
使用自定义控件:
objectivec
@interface ViewController () <CustomViewDelegate>
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
CustomView *customView = [[CustomView alloc] initWithFrame:self.view.bounds];
customView.delegate = self;
[self.view addSubview:customView];
}
// CustomViewDelegate 方法
- (void)customViewButtonWasTapped {
NSLog(@"Button was tapped in custom view.");
}
@end
4. 事件的传递与回调
在对象之间需要传递事件或执行回调时,Delegate 是一种常用方案。
- 例如:网络请求完成后,将结果返回给调用者。
- 例如:任务完成通知某个对象。
5. 解耦设计
Delegate 可以用于降低对象之间的耦合度。例如:
- UITableView 和其数据源分离,控制器实现协议方法,而 UITableView 并不知道具体实现。
- MVC 架构中,Controller 与 View 通过 Delegate 通信,解耦逻辑与界面代码。
6. 常见框架与委托
- UITableViewDelegate / UITableViewDataSource:表格视图事件与数据源回调。
- UICollectionViewDelegate / UICollectionViewDataSource:集合视图的数据源与事件处理。
- UITextFieldDelegate:文本输入控件的事件回调。
- NSURLSessionDelegate:网络请求结果的回调。
- CLLocationManagerDelegate:位置服务的事件回调。
最佳实践:对于单一事件回调,推荐使用 Block,而对于复杂逻辑、多方法回调,使用 Delegate 模式更合适。