OC - 多代理的实现

一、背景

迭代项目的时候碰到一个问题, 原因是负责的内容有一项是封装各大 AI 开放平台的 SDK 集成到一个 SDK 里,然后输出统一的接口,目的是为了可以在不同的 AI 中快速切换并使用。但由于之前输出给了兄弟公司使用,他们在一个音乐 SDK 中用语音 SDK 实现语音点歌的功能。然后当我的主应用同时使用两个 SDK 时,由于音乐 SDK 中实现了语音 SDK 的代理,所以我在上层再初始化语音 SDK 设置代理就不起作用。

二、解决方式

知道问题原因后,就比较容易解决了,具体有几种思路:

  1. 打电话给兄弟公司的开发人员,你不要这样弄了,如果你非要这么弄,就暴露一个接口给我,让我选择是否要让你初始化。
  2. 延迟上层语音 SDK 的初始化,不和你抢代理的设置,就不存在被抢夺这件事了。
  3. 语音 SDK 实现多代理——既然你们都要实现我的代理方法,我就全部都给你们。

作为一个有追求的开发仔,当然选择实现最高难度的自己实现多代理的方式——虽然由于时间关系,也用了第二种方式作为缓冲,然后也发现第二种方式存在一个问题,就是当网络较差的情况下,未能初始化成功,在初始化成功后,音乐 SDK 又会设置一次语音 SDK 的代理,又被抢回去了~

三、具体实现

实现的过程中,以下几篇文章的内容给了我很大的帮助:

两篇文章都讲的很细,所以对于有些细节就不展开讲了,只讲一下具体实现原理:

  1. 首先理解代理模式。也就是由一个对象 A 通过他的唯一一个代理成员把消息发个对象 B。
  2. 多代理就是在第一步的基础上,把对象 A 的代理成员从唯一一个,拓展为多个,消息接收者也从单一的 B,可以延伸为 B1、B2、B3…Bx。

所以实现的时候很简单。

1.定义一个储存多个代理成员的数组:

1
2
3
4
5
6
7
8
@property (strong, nonatomic) NSPointerArray* delegates;

-(NSPointerArray *)delegates{
if (!_delegates) {
_delegates = [[NSPointerArray alloc]init];
}
return _delegates;
}

2.重写代理的 set 方法

1
2
3
4
5
6
7
8
9
- (void)setDelegate:(id<ManagerDelegate>)delegate{

for (id existDelegate in self.delegates) {
if ([delegate isEqual:existDelegate]) {
return;
}
}
[_delegates addPointer:(__bridge void*)delegate];
}

3.多代理响应

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
- (void)asrResultIsTimeOut{
if (self.currentCount != 0) {
self.currentCount--;
}else{
[self.asrTimer invalidate];
self.asrTimer = nil;
for (id delegate in self.delegates) {
if ([delegate respondsToSelector:@selector(asrManagerActiveError:)]) {
[delegate asrManagerActiveError:NETWORKERROR];
}
}

//原始响应方法
// if ([self.asrDelegate respondsToSelector:@selector(asrManagerActiveError:)]) {
// [self.asrDelegate asrManagerActiveError:TIMEOUT];
// }
}
}

四、拓展阅读

在实现的过程中,我一开始用的是 NSMutableArray,因为使用运行也没有什么问题,但看到👆多代理文章里说,用 NSPointerArray 会好点,不增加成员的应用计数,相当于弱引用。听起来不错哦,但忽然之前想到一个问题,为什么 delegate 一一定要用 weak 引用呢,这个问题之前一直没仔细去思考过,像灯下黑,一直用的反倒忽略了。当下,想起来就去百度了一下。在这里看到:iOS 代理为啥要用weak修饰? (刨根问底一)——刨根问底的副标题深得我心~,里面有生动详细的例子说明,简单来说就是强引用会出现循环引用的问题。