## 視圖層的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
~~~