通常情况下,视图层只是简单负责数据展示和负责将事件响应转交给控制器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模式一文。在这种代码结构中,如果V
层决定了控制器接下来的跳转,那么可以考虑将跳转的业务迁移到V
中执行。通过事件链查找的方式获取所在的控制器,这一过程并不能说违背了MVC
的访问限制原则,在整个过程中V
不在乎其所在的currentController
和nextController
的具体类型,通过自定义一个协议来在跳转前将nextController
发送给当前控制器完成跳转前的配置。
这里要注意的是,Self-Manager有其特定的使用场景。当视图层的回调处理需要两层或者更多的时候,Self-Manager能有效的执行
如果抽离的足够高级,甚至可以定义一个同一个的Self-Manager
协议来提供给自定义视图完成这些工作。这样同一套业务逻辑可以给任意的自定义视图复用,只要其符合视图<->控制器
的捆绑关系。:
@protocol LXDViewSelfManager <NSObject> @optional - (void)customView: (UIView *)customView transitionToController: (UIViewController *)nextController; @end
- 文章导航