你是否在維護SocketRocket項目中的TestChat模塊時遇到過ViewController代碼臃腫、業務邏輯與UI強耦合的問題?本文將以TestChat模塊為例,詳細講解如何通過MVVM架構遷移解決這些痛點,使代碼更易維護和擴展。
重構前MVC架構分析
TestChat模塊原採用MVC架構,核心代碼集中在TCViewController.m中。該文件存在以下典型問題:
- 職責過重:同時承擔網絡通信(SRWebSocketDelegate)、UI更新、數據處理等任務
- 數據與UI強耦合:直接在控制器中管理消息數組
_messages並處理表格刷新 - 測試困難:業務邏輯難以單獨測試
關鍵代碼示例:
// TCViewController.m 中混合的數據處理與UI邏輯
- (void)_addMessage:(TCMessage *)message {
[_messages addObject:message];
[self.tableView insertRowsAtIndexPaths:@[ [NSIndexPath indexPathForRow:_messages.count - 1 inSection:0] ]
withRowAnimation:UITableViewRowAnimationNone];
[self.tableView scrollRectToVisible:self.tableView.tableFooterView.frame animated:YES];
}
MVVM架構設計方案
架構分層
遷移後的架構包含以下核心組件:
核心模塊劃分
- Model層:TCMessage.h保持不變,專注數據存儲
- ViewModel層:新增TCChatViewModel.h處理業務邏輯
- View層:TCViewController.h僅負責UI展示與事件轉發
- 網絡層:封裝SRWebSocket通信邏輯到獨立服務類
分步遷移實現
1. 創建ViewModel層
新建TCChatViewModel.h和TCChatViewModel.m,將原ViewController中的業務邏輯遷移至此:
// TCChatViewModel.h
#import <Foundation/Foundation.h>
#import "TCMessage.h"
@interface TCChatViewModel : NSObject
@property (nonatomic, readonly) NSArray<TCMessage *> *messages;
@property (nonatomic, copy) void (^onMessagesUpdated)(void);
- (void)connectToServer;
- (void)sendMessage:(NSString *)message;
- (void)sendPing;
@end
2. 重構ViewController
修改TCViewController.m,使其通過綁定ViewModel實現UI更新:
// 重構後的ViewController
@implementation TCViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.viewModel = [[TCChatViewModel alloc] init];
__weak typeof(self) weakSelf = self;
self.viewModel.onMessagesUpdated = ^{
[weakSelf.tableView reloadData];
};
[self.viewModel connectToServer];
}
// 移除原有數據處理邏輯,直接從ViewModel獲取數據
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.viewModel.messages.count;
}
@end
3. 網絡通信封裝
創建TCWebSocketService.h封裝SocketRocket通信邏輯:
// TCWebSocketService.h
#import <Foundation/Foundation.h>
#import <SocketRocket/SocketRocket.h>
@interface TCWebSocketService : NSObject <SRWebSocketDelegate>
+ (instancetype)sharedInstance;
- (void)connect:(NSString *)url;
- (void)sendMessage:(NSString *)message;
@end
重構效果對比
代碼結構優化
|
模塊
|
重構前代碼量
|
重構後代碼量
|
職責清晰度
|
|
TCViewController.m
|
194行
|
87行
|
大幅提升
|
|
新增ViewModel
|
0行
|
120行
|
單一職責
|
|
新增Service
|
0行
|
95行
|
職責明確
|
可維護性提升
- 關注點分離:網絡邏輯、業務處理、UI展示完全分離
- 可測試性:ViewModel可獨立進行單元測試
- 擴展性:新增功能只需擴展ViewModel,無需修改ViewController
遷移注意事項
- 依賴注入:通過構造函數傳遞依賴,便於測試
- 綁定機制:可使用KVO或第三方框架實現ViewModel與View的響應式綁定
- 增量遷移:建議按功能模塊逐步遷移,而非一次性重寫
總結與展望
通過MVVM架構遷移,TestChat模塊代碼質量得到顯著提升。後續可進一步引入ReactiveCocoa實現更優雅的數據綁定,或參考SocketRocketTests中的測試結構為新架構添加完整測試覆蓋。
重構後的代碼結構遵循了開閉原則,為未來功能擴展奠定了良好基礎。建議在其他類似模塊中推廣這種架構模式,提升整個SocketRocket項目的代碼質量。