美文网首页iOS-Block相关
iOS Block一对多回调的实现

iOS Block一对多回调的实现

作者: 尘埃Wang | 来源:发表于2019-07-19 17:04 被阅读0次

前言

我们都知道,回调的方案有Block、代理、通知。要想实现一对多就要用通知。而且很方便的在多个地方进行回调,实现我们任意的方法。
然而是否考虑过用Block去实现一对多的回调。注意:不是无聊的想象哦,可以让我们看到另一面。

原理

一般情况下,Block的回调确实是一对一的。要想实现一对多,我们能想到什么?缓存block,循环调用。没错,本质上是这样。现在我们需要考虑一下几个问题:

1、用什么缓存来保证不会循环引用?
2、Block的一对一?
3、如何遍历调用?
4、还有不想用的Block如何快捷移除?

下面我们来一一解决以上问题。

实现方案

1、第一个问题:
首先我们可以考虑使用 NSMapTable 来缓存Block。因为这种缓存方式可以设置KEY和Value的缓存策略,并且可以把KEY设置成Object。设置Value的缓存策略,可以让我们把绑定的Block的Target也就是我们Value设置成 NSPointerFunctionsWeakMemory 这样就可以在Target释放的时候,自动移除我们的此条数据。

2、第二个问题
我们可以使用 runtime 的关联对象,关联当前监听对象 observer 和Block。

3、第三个问题
遍历的时候,遍历所有的存储的 observer,找出其相对应的KEY,再用KEY找到所关联的Block。从而实现回调。

4、第四个问题
其实第四个问题,在第一个问题的基础上也已经得到了解决。但是我们有可能在一个类里,也就是同一个Observer中有多个回调,此时我们需要的KeyTable中的数据无法移除。此时单独Remove即可

具体实现如下:

@interface Manger ()

@property (nonatomic, strong) NSMapTable *valueTable;

@property (nonatomic, strong) NSMapTable *keyTable;

@end
@implementation Manger

+ (instancetype)sharedInstance
{
    static Manger *gInteractor = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        if (!gInteractor) {
            gInteractor = [Manger new];
            gInteractor.valueTable = [NSMapTable mapTableWithKeyOptions:NSMapTableStrongMemory valueOptions:NSMapTableWeakMemory];
            gInteractor.keyTable = [NSMapTable mapTableWithKeyOptions:NSMapTableStrongMemory valueOptions:NSMapTableWeakMemory];
        }
    });
    return gInteractor;
}

- (void)clickSelector:(id)obsever callBack:(void(^)(NSString *callStr))callBack {
    
    // 使用内存地址保证一个对象置监听一次
    NSString *key = [NSString stringWithFormat:@"%@-key", [NSString stringWithFormat:@"%p", obsever]];
    NSString *keyValue = [key stringByAppendingString:@"-KeyBlock"];
    
    [self.valueTable setObject:obsever forKey:key];
    [self.keyTable setObject:keyValue forKey:key];
    
    // keyValue 和 block 进行关联
    objc_setAssociatedObject(obsever, CFBridgingRetain(keyValue), callBack, OBJC_ASSOCIATION_COPY);
}

- (void)clickSelector {
    
    NSArray <NSString *>*keyArr = [[self.valueTable keyEnumerator] allObjects];
    
    [keyArr enumerateObjectsUsingBlock:^(NSString * _Nonnull key, NSUInteger idx, BOOL * _Nonnull stop) {
        
        id observe = [self.valueTable objectForKey:key];
        NSString *valueKey = [self.keyTable objectForKey:key];
        void(^block)(NSString *callStr) = objc_getAssociatedObject(observe, (__bridge const void * _Nonnull)(valueKey));
        
        if (block) {
            block([NSString stringWithFormat:@"%@", NSStringFromClass([self class])]);
        }
    }];
    
    NSLog(@"%@\n%@", self.valueTable, self.keyTable);
}

/// 移除的时候,仅仅只是移除的KeyTable数据,因为ValueTable中的数据,随着Observer的释放而自动移除了
- (void)remove:(id)obj {
    
    NSString *key = [NSString stringWithFormat:@"%@-key", [NSString stringWithFormat:@"%p", obj]];
    [self.keyTable removeObjectForKey:key];
}

@end

相关文章

  • iOS Block一对多回调的实现

    前言 我们都知道,回调的方案有Block、代理、通知。要想实现一对多就要用通知。而且很方便的在多个地方进行回调,实...

  • 面试题 - iOS中如何用Block实现一对多回调

    之前面试的时候被面试官问到 “如何使用block实现一对多回调”,那会儿只知道回调分两种,第一种是一对一的,就是常...

  • 一对多回调例程

    在C++11中,借助variadic template,实现最简单的(trivial)的一对多回调。 boost:...

  • iOS-2 Block

    block块 系列文章: iOS Block浅浅析 - 简书 iOS Block实现原理 iOS Block __...

  • ios 委托(delegate)和block 传值

    委托和block是IOS上实现回调的两种机制。Block基本可以代替委托的功能,而且实现起来比较简洁,比较推荐能用...

  • Objc Block实现分析

    Objc Block实现分析 Block在iOS开发中使用的频率是很高的,使用的场景包括接口异步数据的回调(AFN...

  • iOS Block存储域及循环引用

    系列文章:iOS Block概念、语法及基本使用iOS Block实现原理iOS Block __block说明符...

  • Block实现iOS回调

    回调函数是我们在编程中经常使用到的,但是很多新手只知道怎么用,不知其所以然。今天我们就来剖析下回调函数到底是个什么...

  • 关于XMPPFramwork中使用的多播代理

    在IOS中为了实现回调一般有如下几个方法: delegate NSNotification block4 .KVO...

  • Note_UIAlertController

    UIAlertController作为iOS8新特性,按键的触发方法采用block回调方式实现,一改UIActio...

网友评论

    本文标题:iOS Block一对多回调的实现

    本文链接:https://www.haomeiwen.com/subject/kosslctx.html