4.视图层的Self-Manager

最后更新于:2022-04-01 16:18:23

## 视图层的Self-Manager 通常情况下,视图层只是简单负责数据展示和负责将事件响应转交给控制器`C`层执行,创建视图的代码都在控制器层中完成,因此`V`层的状态也不见得比`M`好得多。比如当我自定义一个扇形展开的菜单视图,在点击时的响应: ~~~ //LXDMenuView.m - (void)clickMenuItem: (LXDMenuItem *)menuItem { if ([_delegate respondsToSelector: @selector(menuView:didSelectedItem:)]) { [_delegate menuView: self didSelectedItem: menuItem.tag]; } } //ViewController.m - (void)menuView: (LXDMenuView *)menuView didSelectedItem: (NSInteger)index { Class controllerCls = NSClassFromString(_controllerNames[index]); UIViewController *nextController = [[controllerCls alloc] init]; [self.navigationController pushViewController: nextController animated: YES]; } ~~~ 这段代码是最常见的`视图->控制器`事件处理流程,当一个控制器界面的自定义视图、控件响应事件过多的时候,即便我们已经使用`#pragma mark -`的方式将这些事件进行分段,但还是会占用过大的代码量。`MVC`公认的问题是`C`完成了太多的业务逻辑,导致过胖,跟`M`层的处理一样的,笔者同样将一部分弱业务转移到`V`层上,比如上面的这段页面跳转: ~~~ @interface LXDMenuView: UIView @property (nonatomic, strong) NSArray<NSString *> * itemControllerNames; @end @implementation LXDMenuView - (void)clickMenuItem: (LXDMenuItem *)menuItem { UIViewController *currentController = [self currentController]; if (currentController == nil) { return; } Class controllerCls = NSClassFromString(_itemControllerNames[menuItem.tag]); UIViewController *nextController = [[controllerCls alloc] init]; if ([currentController respondsToSelector: @selector(menuView:transitionToController:)]) { [currentController menuView: self transitionToController: nextController]; } [currentController.navigationController pushViewController: nextController animated: YES]; } - (UIViewController *)currentController { UIResponder *nextResponder = self.nextResponder; while (![nextResponder isKindOfClass: [UIWindow class]]) { if ([nextResponder isKindOfClass: [UIViewController class]]) { return (UIViewController *)nextResponder; } nextResponder = nextResponder.nextResponder; } return nil; } @end ~~~ 这种业务转移的思路来自于[开发中的Self-Manager模式](http://blog.sunnyxx.com/2015/12/19/self-manager-pattern-in-ios/)一文。在这种代码结构中,如果`V`层决定了控制器接下来的跳转,那么可以考虑将跳转的业务迁移到`V`中执行。通过[事件链查找](http://www.jianshu.com/p/a8926633837b)的方式获取所在的控制器,这一过程并不能说违背了`MVC`的访问限制原则,在整个过程中`V`不在乎其所在的`currentController`和`nextController`的具体类型,通过自定义一个协议来在跳转前将`nextController`发送给当前控制器完成跳转前的配置。 > 这里要注意的是,Self-Manager有其特定的使用场景。当视图层的回调处理需要两层或者更多的时候,Self-Manager能有效的执行 如果抽离的足够高级,甚至可以定义一个同一个的`Self-Manager`协议来提供给自定义视图完成这些工作。这样同一套业务逻辑可以给任意的自定义视图复用,只要其符合`视图<->控制器`的捆绑关系。: ~~~ @protocol LXDViewSelfManager <NSObject> @optional - (void)customView: (UIView *)customView transitionToController: (UIViewController *)nextController; @end ~~~
';