共享密钥,多方共享,iOS实现一对多代理方案揭秘
2023-11-08 06:45:11
“多线程是苹果爆炸的导火索,而代理就是那枚地雷。”
毫无疑问,代理模式在iOS应用开发中的使用非常广泛。苹果给了我们一个相当简单的解决方案去实现某些有趣的事情,甚至苹果官方也相当鼓励用代理模式去解决很多问题,就好像给一台汽车加装了四轮涡轮增压器和四个尾翼。
当然,这不是一篇文章的核心。我们先来聊聊代理的分类:
-
一对一代理: 一个代理对象只服务于一个目标对象。这是一个最常见的代理类型。比如说,在iOS系统中,当我们通过
UITableView
来展示数据时,为了让它显示数据,就必须有一个数据源对象。而这个数据源,在代理模式中,就是目标对象。而我们的UITableView
,就是代理对象,因为UITableView
会从数据源中去获取数据来展示。 -
一对多代理: 一个代理对象可以服务于多个目标对象。这是我们今天要介绍的代理类型,而这种代理也可以称之为多路复用代理。
-
多对一代理: 多个代理对象服务于一个目标对象。这种代理类型使用较少,原因在于它更多用于一种设计模式而不是一种代理。在实际应用中,多对一代理经常被认为是多目标模式或多委托模式。
-
多对多代理: 多个代理对象服务于多个目标对象。这种代理类型和多对一代理一样,多用于一种设计模式而不是一种代理。
现在,我们已经弄清楚代理的分类,那我们来讲讲如何实现一对多代理。首先,我们先看看一对一代理的实现:
@interface ViewController : UIViewController <UITableViewDataSource>
@property (nonatomic, strong) UITableView *tableView;
@property (nonatomic, strong) NSMutableArray *dataSource;
- (void)viewDidLoad {
[super viewDidLoad];
// 初始化tableView
self.tableView = [[UITableView alloc] initWithFrame:self.view.bounds];
self.tableView.dataSource = self;
// 初始化dataSource
self.dataSource = [NSMutableArray array];
// 添加数据到dataSource
[self.dataSource addObject:@"数据1"];
[self.dataSource addObject:@"数据2"];
[self.dataSource addObject:@"数据3"];
}
#pragma mark - UITableViewDataSource
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.dataSource.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"cell"];
}
cell.textLabel.text = self.dataSource[indexPath.row];
return cell;
}
@end
这个示例中,ViewController
就是代理对象,UITableView
就是目标对象。ViewController
实现了UITableViewDataSource
协议,这使它能够成为UITableView
的数据源。然后,我们在viewDidLoad
方法中初始化了UITableView
和dataSource
,并添加了一些数据到dataSource
中。最后,我们实现了UITableViewDataSource
协议中的两个方法,这两个方法分别是tableView:numberOfRowsInSection:
和tableView:cellForRowAtIndexPath:
,这两个方法返回UITableView
中行的数量和每个单元格中的数据。
那我们该如何实现一对多代理呢?只需几步:
- 创建一个可变数组来存储代理对象。
- 在代理对象的初始化方法中,将代理对象添加到可变数组中。
- 在目标对象中,遍历可变数组中的代理对象,并调用它们的代理方法。
@interface Target : NSObject
@property (nonatomic, strong) NSMutableArray *delegates;
- (void)doSomething;
@end
@implementation Target
- (instancetype)init {
self = [super init];
if (self) {
self.delegates = [NSMutableArray array];
}
return self;
}
- (void)doSomething {
for (id delegate in self.delegates) {
if ([delegate respondsToSelector:@selector(targetDidSomething:)]) {
[delegate targetDidSomething:self];
}
}
}
- (void)addDelegate:(id)delegate {
[self.delegates addObject:delegate];
}
- (void)removeDelegate:(id)delegate {
[self.delegates removeObject:delegate];
}
@end
@interface DelegateA : NSObject <TargetDelegate>
@end
@implementation DelegateA
- (void)targetDidSomething:(Target *)target {
NSLog(@"DelegateA received message from Target");
}
@end
@interface DelegateB : NSObject <TargetDelegate>
@end
@implementation DelegateB
- (void)targetDidSomething:(Target *)target {
NSLog(@"DelegateB received message from Target");
}
@end
int main() {
Target *target = [[Target alloc] init];
DelegateA *delegateA = [[DelegateA alloc] init];
DelegateB *delegateB = [[DelegateB alloc] init];
[target addDelegate:delegateA];
[target addDelegate:delegateB];
[target doSomething];
[target removeDelegate:delegateA];
[target doSomething];
return 0;
}
在上面的示例中,Target
类是目标对象,而DelegateA
和DelegateB
类是代理对象。Target
类有一个名为delegates
的可变数组,用来存储代理对象。Target
类还实现了doSomething
方法,该方法遍历delegates
数组中的代理对象,并调用它们的代理方法。DelegateA
和DelegateB
类都实现了TargetDelegate
协议,该协议包含一个名为targetDidSomething:
的方法。当Target
类的doSomething
方法被调用时,它会遍历delegates
数组中的代理对象,并调用它们的targetDidSomething:
方法。这样,DelegateA
和DelegateB
类就会收到Target
类的消息,并作出相应的反应。
最后,我们再来说说需要注意的地方:
- 由于数组是强引用,因此,我们需要在合适的地方释放它,以避免内存泄漏。
- 使用一对多代理时,需要谨慎地管理代理对象的生命周期,以确保它们不会在目标对象之前被释放。
希望本文能帮助您更好地理解一对多代理以及如何实现它。如果您有任何问题或建议,请随时留言。