相信是個(gè)iOS程序猿都寫過(guò)UIViewController,同時(shí)也都知道iOS是一個(gè)標(biāo)準(zhǔn)的MVC,也是蘋果推薦的設(shè)計(jì)模式,小編認(rèn)為最典型的Demo算是UITableViewController了。

MVC發(fā)展的比較早,也比較完善,在MVC設(shè)計(jì)模式具有可靠性,健壯性等優(yōu)點(diǎn)的同時(shí),也不能忽略他的缺點(diǎn),那就是Controller太過(guò)于臃腫,其功能不僅僅是View與Model的協(xié)調(diào)控制,還包括以下業(yè)務(wù)功能:
- 網(wǎng)絡(luò)請(qǐng)求與數(shù)據(jù)處理
- View動(dòng)畫與ViewController跳轉(zhuǎn)
- 日志統(tǒng)計(jì)等繁雜功能

以今日頭條為例,今日頭條的視頻播放頁(yè)有太多功能了,大體上分為:
- 視頻播放器
- 推薦視頻列表(還有查看更多等功能)
- 廣告
- 評(píng)論功能
- 底部ToolBar功能
很多開(kāi)始擼iOS的人第一時(shí)間是在一個(gè)UIViewController上碼上所有的代碼,稍微有點(diǎn)經(jīng)驗(yàn)的還會(huì)進(jìn)行拆分比如:將播放器拆分成一個(gè)獨(dú)立的View,然后評(píng)論TableView拆分,再將底部TooBar拆分,再將這三個(gè)組件堆到UIViewController上。
但是這個(gè)樣子還是無(wú)法從根本上為UIViewController瘦身,代碼也絕對(duì)不會(huì)少,比如評(píng)論等相關(guān)的頁(yè)面跳轉(zhuǎn)與數(shù)據(jù)請(qǐng)求業(yè)務(wù)還得放到UIViewController去處理。同時(shí)拓展也很差,比如我想present到一個(gè)全屏播放器,那還要根據(jù)這個(gè)播放器View自定制一個(gè)UIViewController,太Low了。
實(shí)際上,蘋果提供了解決這種缺陷的方法,那就是:Container(容器)。最常見(jiàn)的方法如下:
- (void)addChildViewController:(UIViewController *)childController NS_AVAILABLE_IOS(5_0);
- (void)removeFromParentViewController NS_AVAILABLE_IOS(5_0);
- (void)willMoveToParentViewController:(nullable UIViewController *)parent NS_AVAILABLE_IOS(5_0);
- (void)didMoveToParentViewController:(nullable UIViewController *)parent NS_AVAILABLE_IOS(5_0);
從上面蘋果提供的四個(gè)方法可以相信:它像極了addSubView,只不過(guò)是從View改變到UIViewController罷了。
廢話不多說(shuō),這下子就來(lái)拆分模塊(現(xiàn)在流行叫組件,業(yè)務(wù)組件):
- 將視頻播放器作為一個(gè)模塊,內(nèi)聚到一個(gè)UIViewController上
- 推薦視頻列表,廣告,評(píng)論等功能內(nèi)聚到一個(gè)UIViewController上(評(píng)論本該是獨(dú)立出來(lái),但是從這里來(lái)看應(yīng)該是不能獨(dú)立的)
- 底部的ToolBar
模塊拆分完畢之后就該整合了,方案是:定義一個(gè)叫做LCVideoContainerController,在里面存放上面提到的三個(gè)模塊。代碼如下:
// LCVideoModel作為模塊之間傳遞信息的媒介
LCVideoModel *videoModel = self.videoModel;
// 視頻播放器
self.videoViewController = [[LCVideoViewController alloc] initWithVideoModel:videoModel];
[self addChildViewController:self.videoViewController];
[self.view addSubview:self.videoViewController.view];
[self.videoViewController didMoveToParentViewController:self];
// 推薦列表
self.recommendationController = [[LCRecommendationTableController alloc] initWithStyle:UITableViewStylePlain];
self.recommendationController.tableView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
[self addChildViewController:self.recommendationController];
[self.view addSubview:self.recommendationController.view];
[self.recommendationController didMoveToParentViewController:self];
// 底部ToolBar
self.commentToolBar = [[LCCommentToolBar alloc] init];
[self.view addSubview:self.commentToolBar];
搭建好約束之后,效果圖如下:

如此看來(lái)LCVideoContainerController這個(gè)類里的代碼就少多了,其功能就是:整合播放器,評(píng)論,ToolBar等controller和view,同時(shí)橫豎屏相關(guān)的操作也是在這里完成。這就是iOS開(kāi)發(fā)當(dāng)中的Container的使用,可以直觀的理解成:在MVC設(shè)計(jì)模式中的Controller之外,還有一個(gè)控制Controller的Container。
除了Container能達(dá)到UIViewController瘦身之外,利用MVVM設(shè)計(jì)模式也是可以達(dá)到瘦身效果的,最常見(jiàn)的就是將數(shù)據(jù)請(qǐng)求等業(yè)務(wù)集成到一個(gè)View-Model當(dāng)中,以下便是MVVM設(shè)計(jì)模式的關(guān)系圖:

不過(guò)在我個(gè)人看來(lái):為UIViewController瘦身時(shí),MVVM設(shè)計(jì)模式只能是錦上添花,而Container才是能最大限度的達(dá)到瘦身效果。
Github:播放器架構(gòu)。