GCDMulticastDelegate多播委托

在iOS中实现回调的机制有以下几种:

1.block
2.通知
2.kvo
4.delegate
其中比较常用的是delegate和block,通知其次,最后才是KVO.

回调的话,既可以有1对1,也可以1对多。分类
1对1的回调
1对多的回调
从分类上看,block和delegate可以实现1对1的回调。
通知可以实现1对多的回调。

假如现在有一个需求,我们以图片下载为例。这里先忽略哪些SDWebimage等已经封装好的第三方类库。对于图片下载一般的过程如下:

先判断该图片url是否已经下载完毕。如果已经下载完毕那么直接回调显示图片。如果没有下载那么进入下载过程.
使用合适的图片下载器下载图片。
图片下载完毕后回调显示图片。并且把该图片存到缓存中。
这里的难点是回调。如果一个页面中有多个地方需要显示同一张图片,那么势必会发生这样一种情况,就是同时有多个请求下载同意url的图片,并且下载完成后需要同时在多个地方显示图片。要是实现这样的需求,用现有的方案貌似很难解决。有的同学会想到通知中心,但是通知中心其实是一个广播服务,只要注册了接受该通知那么所有的注册者都能收到通知,但事实上我只需要在我需要下载的那个url的图片下载完后给出通知,而不需要所有的下载完毕事件都通知。这时候我们就需要多播委托了。

什么是多播委托?我直接拿其他博客上的一个定义来解释。简单地说,多播委托是指允许创建方法的调用列表或者链表的能力。当多播委托被调用时,列表中的方法均自动执行

在IOS中我就以我们平常用的最多的delagate为例,普通的delegate只能是一对一的回调,无法做到一对多的回调。而多播委托正式对delegate的一种扩展和延伸,多了一个注册和取消注册的过程,任何需要回调的对象都必须先注册。

如何在IOS中实现多播委托?老外早就已经写好了,而且相当的好用。我最初接触IOS多播委托是我在研究XMPPframework的时候,而多播委托可以说是XMPPframework架构的核心之一。具体的类名就是GCDMulticastDelegate,从名字就可以看出,这是一个支持多线程的多播委托。那为什么要支持多线程呢?我的理解是多个回调有可能不是在同一个线程的,比如我注册回调的时候是在后台线程,但是你回调的时候却在UI线程,那就有可能出问题了。因此必须保证你注册的时候在哪个线程上注册的,那么回调的时候必须还是在那个线程上回调的。

GCDMulticastDelegate是XMPPFrameWork开源框架中使用的一个类,它主要是处理收到信息后,多处转发信息。实现的原理其实是比较简单的,就是利用object-c的消息传递机制。

这个类中有3个Interface:

CGDMulticastDelegate(主),GCDMulticastDelegateNode,GCDMulticastDelegateEnumerator

他们之间的关系图如下:

GCDMulticastDelegate多播委托_第1张图片

三个类的内容:

GCDMulticastDelegateNode:

@interface BIMGCDMulticastDelegateNode : NSObject {
@private

  #if __has_feature(objc_arc_weak)
    __weak id delegate;
  #if !TARGET_OS_IPHONE
    __unsafe_unretained id unsafeDelegate; // Some classes don't support weak references yet (e.g. NSWindowController)
  #endif
  #else
    __unsafe_unretained id delegate;
  #endif

    dispatch_queue_t delegateQueue;
}

- (id)initWithDelegate:(id)delegate delegateQueue:(dispatch_queue_t)delegateQueue;

#if __has_feature(objc_arc_weak)
@property (/* atomic */ readwrite, weak) id delegate;
#if !TARGET_OS_IPHONE
@property (/* atomic */ readwrite, unsafe_unretained) id unsafeDelegate;
#endif
#else
@property (/* atomic */ readwrite, unsafe_unretained) id delegate;
#endif

@property (nonatomic, readonly) dispatch_queue_t delegateQueue;

/** 添加 **/

@property (nonatomic, strong) NSString *key;

@end

这个类相当于一个对象Model,负责将传进来的一个代理对象加工成一个Node对象,处理后的对象是后面两个类的操作对象。

GCDMulticastDelegateEnumerator:

@interface BIMGCDMulticastDelegateEnumerator : NSObject
 - (NSUInteger)count;
- (NSUInteger)countOfClass:(Class)aClass;
- (NSUInteger)countForSelector:(SEL)aSelector;

- (BOOL)getNextDelegate:(id *)delPtr delegateQueue:(dispatch_queue_t *)dqPtr;
- (BOOL)getNextDelegate:(id *)delPtr delegateQueue:(dispatch_queue_t *)dqPtr ofClass:(Class)aClass;
- (BOOL)getNextDelegate:(id *)delPtr delegateQueue:(dispatch_queue_t *)dqPtr forSelector:(SEL)aSelector;

@end

辅助类,

BIMGCDMulticastDelegate

@interface BIMGCDMulticastDelegate : NSObject

- (void)addDelegate:(id)delegate delegateQueue:(dispatch_queue_t)delegateQueue;
- (void)removeDelegate:(id)delegate delegateQueue:(dispatch_queue_t)delegateQueue;
- (void)removeDelegate:(id)delegate;

- (void)removeAllDelegates;

- (NSUInteger)count;
- (NSUInteger)countOfClass:(Class)aClass;
- (NSUInteger)countForSelector:(SEL)aSelector;

- (BOOL)hasDelegateThatRespondsToSelector:(SEL)aSelector;

- (BIMGCDMulticastDelegateEnumerator *)delegateEnumerator;

@end

这个是处理多播委托的主类。

你可能感兴趣的:(ios)