单例使用多代理

问题描述:

tableview有很多cell, 其中有两个cell, 每个cell上有一条音频.

播放音频使用的单例,这个单例有代理方法,在两个cell上都设置代理,但是只有一个代理方法会调用

bug表现就是:

我点击开始播放第一个音频,进度条开始变化, 滑动tableview,上面的进度条不动了,

bug产生的原因是,单例设置多个代理,只有一个代理方法会被调用,代理是一对一的, 如果我想要多个代理方法都执行怎么办呢?

将代理放入数组,遍历这些代理,执行代理函数

具体代码:

.h文件:

@property (nonatomic, strong) NSMutableArray *delegates;

- (void)addDelegate:(NSObject *)foo;

.m文件

- (void)changeStatus:(GXAVPlayStatus)status {if (self.status == status) {
        return;
    }
    __weak typeof(self) weakSelf = self;
    dispatch_async(dispatch_get_main_queue(), ^{
        weakSelf.status = status;
        if (status == GXPlayerPlaying) {
            [weakSelf.progressTimer startTimerWithTime:0.1 target:weakSelf selector:@selector(progressChange) userInfo:nil repeats:true];
        } else if (status != GXPlayerLoading) {
            [weakSelf.progressTimer stopTimer];
        }
        if ([weakSelf.delegate respondsToSelector:@selector(currPlayStatus:)]) {
            [weakSelf.delegate currPlayStatus:status];
        }
        [weakSelf sv_dealStatus:status];
    });
}

- (void)progressChange {
    if (CMTimeGetSeconds(self.currItem.duration) <= 0 || isnan(CMTimeGetSeconds(self.currItem.duration))) {
        return;
    }
    __weak typeof(self) weakSelf = self;
    dispatch_async(dispatch_get_main_queue(), ^{
        if ([weakSelf.delegate respondsToSelector:@selector(progressChange)] && !weakSelf.isSeeking) {
            [weakSelf.delegate progressChange];
        }
        [weakSelf signalDelegateEvent];
    });
    
}

- (void)addDelegate:(NSObject * )foo {
    [self.delegates addObject:foo];
}
- (void)removeDelegate:(NSObject *)foo {
    [self.delegates removeObject:foo];
}
- (void)signalDelegateEvent {
    [self.delegates enumerateObjectsUsingBlock:^(id<SV_GXAVPlayerDelegate> obj,
                                                 NSUInteger idx,
                                                 BOOL *stop) {
        // call delegate method `foo` on each delegate
        if ( [obj respondsToSelector:@selector(sv_progressChange)]) {
            [obj sv_progressChange];
        }
    }];
}

- (void)sv_dealStatus:(GXAVPlayStatus)status; {
    [self.delegates enumerateObjectsUsingBlock:^(id<SV_GXAVPlayerDelegate> obj,
                                                 NSUInteger idx,
                                                 BOOL *stop) {
        // call delegate method `foo` on each delegate
        if ( [obj respondsToSelector:@selector(sv_currPlayStatus:)]) {
            [obj sv_currPlayStatus:status];
        }
    }];
}

-(NSMutableArray *)delegates{
    if(!_delegates){
        _delegates = [NSMutableArray array];
    }
    return _delegates;
}

这样使用多代理,解决了上面提到的bug.

不足之处是,需要恰当的时候释放代理,考虑使用  NSPointerArray; 更好的解决办法是使用runtime。待探索。。。

update: runtime添加多代理:

https://www.jianshu.com/p/fed580fa45eb

https://github.com/FlameGrace/MultiDelegateOC/

https://blog.scottlogic.com/2012/11/19/a-multicast-delegate-pattern-for-ios-controls.html

整体的思路是:

写个NSObject的分类,添加

multiDelegate 属性, 添加addDelegate方法。 这样其他类只要引入这个分类,就可以添加多个代理了

把其他类的代理,设置为multiDelegate

代理调用的时候,在multiDelegate 处理

 

正常的代理,A声明代理,B成为A的代理,  A调用代理,其实是在A类中调用B

 

这里multiDelegate相当于B,   但是multiDelegate没有实现代理方法啊,可以转发, 

respondsToSelector

不明白了,拿过来书看看怎么说的

 主要是 这两个方法,不知道里面啥意思

 

methodSignatureForSelector

forwardInvocation

 

- (void)forwardInvocation:(NSInvocation *)anInvocation {
    NSLog(@"22222222");
    
    for(id delegate in self.delegateArr){
        if ([delegate respondsToSelector:anInvocation.selector]) {
            [anInvocation invokeWithTarget:delegate];
        }
    }
}

- (BOOL)respondsToSelector:(SEL)aSelector{
    if ([super respondsToSelector:aSelector]) {
        return YES;
    }

    for (id target in self.delegateArr) {
        if ([target respondsToSelector:aSelector]) {
            return YES;
        }
    }

    return NO;
}

 

参考下面,可以实现

https://blog.csdn.net/kingjxust/article/details/49559091

TODD:1. 学习下面的;  2. 再写一遍上面的三个方法

https://zhangbuhuai.com/post/message-forwarding.html


2022.3.4更新:

helper类:.m文件

#import "MutipleDelegate3_4_2022.h"

@implementation MutipleDelegate3_4_2022


-(BOOL)respondsToSelector:(SEL)aSelector {

    // 如果父类能响应, 直接返回yes
    if ([super respondsToSelector:aSelector]) {
        return YES;
    }
    
    // 遍历,让代理响应
    for (id delegate in self.delegates) {
        if ([delegate respondsToSelector:aSelector]) {
            return YES;
        }
    }
    
    
    return  NO;
}


-(NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
    NSMethodSignature *sign = [super methodSignatureForSelector:aSelector];
    if (sign) {
        return  sign;
    }else {
        // 每个代理都生成sign
        for(id delegate in self.delegates){
            if ([delegate respondsToSelector:aSelector]) {
                
                // 下面这行没写对,写成了 sign = [delegate methodSignatureForSelector:aSelector];
                return [delegate methodSignatureForSelector:aSelector];
                
            }
        }
        return  sign;
    }
}


- (void)forwardInvocation:(NSInvocation *)anInvocation {
    for(id delegate in self.delegates){
        if ([delegate respondsToSelector:anInvocation.selector]) {
//            [delegate forwardInvocation:anInvocation];
            // 下面这句没抄对. 意思是, anInvocation调用delegate
            [anInvocation invokeWithTarget:delegate];
        }
    }
}


-(NSMutableArray *)delegates {
    if (!_delegates) {
        _delegates = [NSMutableArray array];
    }
    return _delegates;
}

@end

.h文件

#import <Foundation/Foundation.h>


NS_ASSUME_NONNULL_BEGIN

@interface MutipleDelegate3_4_2022 : NSObject
@property (nonatomic, strong) NSMutableArray *delegates;
@end

NS_ASSUME_NONNULL_END

控制器:

#import "MDViewController2022_3_4.h"
#import "HandleDelegateObj.h"
#import "MutipleDelegate3_4_2022.h"

@interface MDViewController2022_3_4 ()<UIScrollViewDelegate>
@property (nonatomic, strong) HandleDelegateObj *obj;
@property (nonatomic, strong) MutipleDelegate3_4_2022 *delegateHelp;
@end

@implementation MDViewController2022_3_4

- (void)viewDidLoad {
    [super viewDidLoad];
    
    UIScrollView *scrl = [[UIScrollView alloc] initWithFrame:CGRectMake(100, 100, 100, 100)];
    [self.view addSubview:scrl];
    scrl.contentSize = CGSizeMake(0, 200);
//    scrl.delegate = self;
    scrl.backgroundColor = [UIColor brownColor];
    
    _obj = [HandleDelegateObj new];
//    scrl.delegate = _obj;
    
    self.delegateHelp = [MutipleDelegate3_4_2022 new];
    self.delegateHelp.delegates = @[self, self.obj];
    
    scrl.delegate = (id<UIScrollViewDelegate>)self.delegateHelp;
    
}

-(void)scrollViewDidScroll:(UIScrollView *)scrollView {
    NSLog(@"控制器滚动");
}

HandleDelegateObj   .h文件

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface HandleDelegateObj : NSObject <UIScrollViewDelegate>

@end

NS_ASSUME_NONNULL_END

.m文件

#import "HandleDelegateObj.h"

@implementation HandleDelegateObj

-(void)scrollViewDidScroll:(UIScrollView *)scrollView {
    NSLog(@"obj滚动了%@",NSStringFromClass([self class]));
}

@end

 

 

 

posted on 2022-03-01 10:36  土匪7  阅读(67)  评论(0编辑  收藏  举报