美文网首页
音视频优化二:控制器瘦身及响应式实现

音视频优化二:控制器瘦身及响应式实现

作者: 某非著名程序员 | 来源:发表于2021-05-21 19:58 被阅读0次

    BLMeetingViewControll瘦身

    音视频优化一做完之后,性能问题没有了。基本可堪重用,但BLMeetingViewControll类的代码量在2000多行,后面又增加了横屏功能。太过臃肿。

    拆完结构.png

    遵循单一职责原则,BLMeetingVCDataSource为底层,所有Control均可使用。
    BLMeetingVCBase为Control父类,有一些共用方法。

    @interface BLMeetingVCBase : NSObject
    @property (nonatomic,weak) BLMeetingViewController * meetingVC;
    @property (nonatomic,weak) BLMeetingVCDataSource * dataSource;
    
    - (instancetype)initWithMeetingVC:(BLMeetingViewController *)meetingVC dataSource:(BLMeetingVCDataSource *)dataSource;
    
    - (BLMeetingVCRequest *)request;
    - (BLMeetingVCRotateControl *)rotateControl;
    - (BLMeetingVCShareControl *)shareControl;
    - (BLMeetingVCMenuControl *)menuControl;
    - (BLMeetingVCLectureControl *)lectureControl;
    - (BLMeetingVCLifeControl *)lifeControl;
    - (BLMeetingVCFloatControl *)floatControl;
    - (UIView *)view;
    
    #pragma mark - 数据源
    - (DolpConferenceProfileDto *)profileDto;
    @end
    
    1. 各Control统一在BLMeetingViewController中创建,可相互调用。
    2. 每个类最多的也就400行,各职责清晰,分享、菜单、主讲、浮窗、旋转等功能。
    3. 拆分也不是一步到位,先拆分到各个分类中,再提取到各control。

    响应式实现

    什么是响应式,一个简单例子a+b=c,当a或b发生变化时,c会自动刷新。这样c就需要监听a和b的属性了。KVO可以胜任,但直接使用系统KVO,如果在dealloc中移除,忘了或者添加多次,或者移除多次都有可能会闪退。

    KVOController第三方库,底层对KVO做了一层封装,不需要管理释放,在观察者对象释放时,会自动移除KVO,一个对象的同一个属性观察者也不会添加多次。

    1. 下面是视频view绑定开关视频、开关摄像头及主持人状态的绑定。
    - (void)bind:(BLMeetingItemModel *)model{
        @weakify(self);
        [self.KVOController observe:model keyPath:@"isOpenMicro" options:NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew block:^(id  _Nullable observer, id  _Nonnull object, NSDictionary<NSString *,id> * _Nonnull change) {
            @strongify(self);
            BOOL isOpenMicro = [change[@"new"] boolValue];
            NSLog(@"%@-%@麦克风",model.nickName,isOpenMicro?@"开启":@"关闭");
            [self.bottomView updateMicroStatus];
        }];
        
        [self.KVOController observe:model keyPath:@"isOpenVideo" options:NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew block:^(id  _Nullable observer, id  _Nonnull object, NSDictionary<NSString *,id> * _Nonnull change) {
            @strongify(self);
            BOOL isOpenMicro = [change[@"new"] boolValue];
            NSLog(@"%@-%@视频-%@",model.nickName,isOpenMicro?@"开启":@"关闭",NSStringFromClass(self.class));
            [self loadVideoSource];
        }];
        
        [self.KVOController observe:model keyPath:@"isHost" options:NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew block:^(id  _Nullable observer, id  _Nonnull object, NSDictionary<NSString *,id> * _Nonnull change) {
            @strongify(self);
            [self.bottomView updateView:model];//更新主持人
        }];
    }
    
    - (void)unbind:(BLMeetingItemModel *)model{
        [self.KVOController unobserve:model keyPath:@"isOpenMicro"];
        [self.KVOController unobserve:model keyPath:@"isOpenVideo"];
        [self.KVOController unobserve:model keyPath:@"isHost"];
    }
    
    1. 主讲模式绑定了远程视频状态,如果有其他人共享,则显示旋转按钮。及按钮旋转状态绑定横竖屏刷新。
    - (void)bind{
        @weakify(self);
        [self.KVOController observe:self.lectureView keyPath:@"showType" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld block:^(id  _Nullable observer, id  _Nonnull object, NSDictionary<NSString *,id> * _Nonnull change) {
            @strongify(self)
            if (self.lectureView.showType == BLShowTypeRemoteShare) {
                [self.rotateControl rotateBtnHidden:NO];
            }else{
                [self.rotateControl rotateBtnHidden:YES];
            }
        }];
    
        [self.KVOController observe:self.rotateControl keyPath:@"orientation" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld block:^(id  _Nullable observer, id  _Nonnull object, NSDictionary<NSString *,id> * _Nonnull change) {
            @strongify(self)
            if (self.rotateControl.orientation == UIInterfaceOrientationPortrait) {
                [self hiddenBottomView:NO];
            }else{
                [self hiddenBottomView:YES];
            }
        }];
    }
    
    1. 美颜与翻转摄像头显示与隐藏绑定开关摄像头;菜单栏绑定横竖屏状态;翻转和主讲按钮绑定分享按钮状态。
    - (void)bind{
        @weakify(self);
        [self.KVOController observe:self.bottomMenuView.cameraButton keyPath:@"selected" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld block:^(id  _Nullable observer, id  _Nonnull object, NSDictionary<NSString *,id> * _Nonnull change) {
            @strongify(self)
            id newValue = change[@"new"];
            BOOL selected = [(NSNumber *)newValue boolValue];
            [self hideCameraReverseAndBeautiful:selected];
        }];
        
        [self.KVOController observe:self.rotateControl keyPath:@"orientation" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld block:^(id  _Nullable observer, id  _Nonnull object, NSDictionary<NSString *,id> * _Nonnull change) {
            @strongify(self)
            self.isHiddenMenu = !self.isHiddenMenu;
            [self menuShowHiddenAnimation];
            
            [self.meetingVC.hostCloseView setFrame:BLKeyWindow.bounds];
            [self.meetingVC.hostCloseView addContentView];
        }];
        
        [self.KVOController observe:self.shareControl keyPath:@"shareType" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld block:^(id  _Nullable observer, id  _Nonnull object, NSDictionary<NSString *,id> * _Nonnull change) {
            @strongify(self)
            BLMeetingShareType shareType = (BLMeetingShareType)[change[@"new"] intValue];
            [self.bottomMenuView shareButtonSelected:shareType == BLMeetingShareTypeLocal];
            [self.bottomMenuView cameraButtonEnable:shareType != BLMeetingShareTypeLocal];//自己分享摄像头置灰,不可点击
            
            if (shareType != BLMeetingShareTypeNone){
                [self.menuControl.topTitleView setRightMenuButtonHidden:YES];//收到屏幕共享:切换摄像头与主讲按钮隐藏
            }else{
                [self.menuControl.topTitleView setRightMenuButtonHidden:NO];
            }
        }];
    }
    
    1. 一个最重要的功能,如何监听数组的变化。
      [self mutableArrayValueForKeyPath:@"dataArray"]可以监听到数组的变化,但存在的问题是监听到的操作不明确。
      removeObjects会调用多次到观察者,removeObject会调用一次,区分不开。如在网络重连时,可能会先remove再addObject,但可能想要的结果只是在所有操作完成后进行一次回调。

    如何很好的监听数组的变化

    一个很好的方式,自定义。
    继承NSMutableArray会有问题,官方文档说明:


    继承NSMutableArray.png

    看了YYThreadSafeArray,发现YY重写了所有的数组方法,内部定义了NSMutableArray *_arr;如果有一个方法漏掉的,程序会直接闪退。有一定风险。

    自定义状态,实现观察:

    typedef enum {
        BLArrayInitType,
        BLArrayAddType,
        BLArrayAddAllType,
        BLArrayRemoveType,
    }BLArrayChangeType;
    
    @property (nonatomic, assign) BLArrayChangeType arrayChangeType;
    
    @weakify(self);
        [self.KVOController observe:self.dataSource keyPath:@"arrayChangeType" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld block:^(id  _Nullable observer, BLMeetingVCDataSource * object, NSDictionary<NSString *,id> * _Nonnull change) {
            @strongify(self);
            if (object.arrayChangeType == BLArrayAddType) {
                NSLog(@"会议:添加数据");
            }else if (object.arrayChangeType == BLArrayAddAllType) {
                NSLog(@"会议:添加数据完成");
            }else if (object.arrayChangeType == BLArrayRemoveType){
                NSLog(@"会议:移除单个数据");
            }
        }];
    

    数组的状态能准确监听。

    响应式的实现,解决了很多刷新问题,如开关摄像头,不再关注联动属性:美颜和翻转按钮的展示了;别人分享,显示旋转按钮;开关摄像头,能够实现局部精准刷新。

    小结

    1. 绑定model,在model需要特殊处理下,如果存在的从缓存中拿,更新对应属性,否则产生新的对象。确保绑定过的对象不会变成另一个。
    2. 数组的监听,自定义更能达到想要的效果。
    3. 绑定遵循原则:谁观察者谁处理,如按钮的隐藏于展示都在菜单的Control中。
    4. tableView的绑定,要注意cell的解绑与重新绑定,滑动当前展示的cell,需要解绑之前的,再绑定当前的。否则会出现绑定多个,而出现展示错误。

    相关文章

      网友评论

          本文标题:音视频优化二:控制器瘦身及响应式实现

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