1.新建PersonalCenterService類,專門處理網絡請求以及model回調。model解析使用第三方YYModel。數據結構爲兩個部分,頭部返回一個字典、第二部分爲一個數組。備註:數據是本身構建的、此過程只是模擬網絡請求過程。json
#import "PersonalCenterService.h"
#import "PersonalCenterModel.h"
@implementation PersonalCenterService
+ (void)getPersonalCenterData:(void(^)(PersonalCenterModel *,NSArray *))successBlock
{
//模擬網絡請求-後臺返回數據
NSDictionary *dictionary = @{
@"head":@{
@"name":@"怪咖君",
@"autograph":@"人生得意須盡歡,莫使金樽空對月",
@"grade":@"青銅",
@"money":@"100",
@"blind":@"2",
@"cardCoupon":@"2",
},
@"rowInfomation":@[
@{@"title":@"支付"},
@{@"title":@"收藏"},
@{@"title":@"卡劵"},
@{@"title":@"用戶反饋"},
@{@"title":@"系統設置"},
]
};
//數據解析
NSDictionary *head = [dictionary objectForKey:@"head"];
//頭部model
PersonalCenterModel*model = [PersonalCenterModel yy_modelWithDictionary:head];
//section->model利用YYModel解析裝入數組、便於操做
NSArray *rowInfomation = [dictionary objectForKey:@"rowInfomation"];
NSArray *dataArray = [NSArray yy_modelArrayWithClass:[personalSecontionModel class] json:rowInfomation];
successBlock(model,dataArray);
}
@end
複製代碼
2.controller中、直接回調block、刷新數據數組
[PersonalCenterService getPersonalCenterData:^(PersonalCenterModel * headModel,NSArray *sectionDataArray) {
//接收數據
self.headModel = headModel;
self.sectionArray = sectionDataArray;
//刷新數據
[self.tableView reloadData];
}];
複製代碼
1.cell子類化bash
自定義TableViewCell、子視圖佈局全放到cell中,cellforRow簡化代碼、不作任何建立子視圖以及添加target事件。網絡
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *identifier = @"TableViewCell";
TableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
if (!cell) {
cell = [[TableViewCell alloc]initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:identifier];
}
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
cell.model = self.dataArray[indexPath.section];
return cell;
}
複製代碼
這樣看起來仍是有點多、咱們自定義BaseCell、cell建立代碼放到BaseCell中。cell相關屬性也放到子cell中。以後就變成以下代碼、簡潔明瞭。數據結構
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
TableViewCell *cell = [TableViewCell cellWithTableView:tableView];
cell.model = self.dataArray[indexPath.section];
return cell;
}
複製代碼
BaseCell你們能夠封裝以下架構
/**
* 建立單元格
*/
+ (instancetype)cellWithTableView:(UITableView *)tableView
{
NSString *className = NSStringFromClass([self class]);
NSString *identifier = [NSString stringWithFormat:@"%@",className];
BaseTableViewCell *baseCell = [tableView dequeueReusableCellWithIdentifier:identifier];
if(baseCell == nil){
baseCell = [[self alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
}
return baseCell;
}
複製代碼
2.HeadView子類化app
HeadViev咱們能夠封裝成一個UIView子類,看成tableViewHeadView處理就行了。點擊事件你們能夠用target-action或者代理以及block等處理,這裏我用了block、簡潔明瞭。ide
- (UIView*)headView
{
PersonalCenterView *centerView = [[PersonalCenterView alloc]initWithFrame:CGRectMake(0, 0, kScreenWidth, 100) clickBlock:^{
//業務操做-根據model判斷等級 進行不一樣的的處理
if ([self.headModel.grade isEqualToString:@"青銅"])
{
[ASRequestHUD showErrorWithStatus:@"您還不具有修改資格,努力升級吧"];
}else if ([self.headModel.grade isEqualToString:@"黃金"])
{
//邏輯處理
}else
{
//鑽石
}
}];
centerView.model = self.headModel;
return centerView;
}
複製代碼
3.數據展現放到view中工具
數據展現、複寫model的set方法就好(你們經常使用的方法,apple的MVC架構中model和View是不能通訊的)佈局
//headView
- (void)setModel:(PersonalCenterModel *)model
{
self.nameLabel.text = model.name;
self.autographLabel.text = model.autograph;
}
//cell
- (void)setModel:(personalSecontionModel *)model
{
self.titleLabel.text = model.title;
}
複製代碼
4.封裝工具類
對於字符串判空、還有提示信息能夠封裝起來。一句話代碼調用就好。以下是註銷模擬過程。ASRequestHUD以及字符串判空、獲取當前控制器等所有封裝成工具類。備註:這裏用註銷過程示例、也是爲了體現Controller處理邏輯業務會佔用太多代碼
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"驗證信息" message:nil preferredStyle:UIAlertControllerStyleAlert];
// 添加文本框
[alertController addTextFieldWithConfigurationHandler:^(UITextField *textField){
textField.placeholder = @"請輸入姓名";
}];
[alertController addTextFieldWithConfigurationHandler:^(UITextField *textField){
textField.placeholder = @"請輸入身份證號碼";
}];
UIAlertAction * firstAction = [UIAlertAction actionWithTitle:@"肯定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action){
UITextField *name= alertController.textFields.firstObject;
UITextField *idCard= alertController.textFields.lastObject;
if ([NSString isEmptString:name.text]&&[NSString isEmptString:idCard.text]) {
[ASRequestHUD showErrorWithStatus:@"信息輸入不完整~"];
return ;
}
//網絡請求1-假設請求成功 處理業務
//網絡請求2-假設請求成功 處理業務
if ([NSString isEmptString:model.money]) {
[ASRequestHUD showErrorWithStatus:@"有餘額未體現,請提現後註銷"];
return;
}else if ([NSString isEmptString:model.blind])
{
[ASRequestHUD showErrorWithStatus:[NSString stringWithFormat:@"您還有%@張卡未解除,請前往解除綁定",model.blind]];
return;
}else if ([NSString isEmptString:model.cardCoupon])
{
[ASRequestHUD showErrorWithStatus:[NSString stringWithFormat:@"您還有%@張優惠卷未使用,請前往刪除或使用",model.cardCoupon]];
return;
}else
{
//網絡請求3-註銷-假設請求成功
//假設須要刷新數據
[self.tableView reloadUI];
}];
UIAlertAction *secondAction = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleDefault handler:nil];
[alertController addAction:firstAction];
[alertController addAction:secondAction];
複製代碼
以上經過提取網絡請求等一系列方法、Controller是瘦身一些。但因爲UITableView協議內容太多、仍然顯得臃腫。如今須要將tableView協議剝離出來,控制器就變得乾淨起來。實現協議最核心的仍是數據源問題,因此咱們只傳入數據源、問題就解決了。
1.定義TableViewData類
#import "TableViewDataSource.h"
#import "TableViewCell.h"
@implementation TableViewDataSource
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return self.dataArray.count;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 1;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
TableViewCell *cell = [TableViewCell cellWithTableView:tableView];
cell.model = self.dataArray[indexPath.section];
return cell;
}
@end
複製代碼
2.定義TableViewDelegate類
@interface TableViewDelegate()
@property(nonatomic ,strong)PresenterPesonalCenter *present;
@end
@implementation TableViewDelegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
//邏輯業務處理-進入詳情頁面
personalSecontionModel *model = self.dataArray[indexPath.section];
PersonalCenterDeatilController *controller = [PersonalCenterDeatilController new];
controller.title = model.title;
[[self jsd_getCurrentViewController].navigationController pushViewController:controller animated:YES];
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 50;
}
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
return 10;
}
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section
{
return 0;
}
- (UIView*)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
return nil;
}
- (UIView*)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section
{
return nil;
}
@end
複製代碼
3.Controller中只要以下代碼就好
//初始化協議
tableDataSource = [[TableViewDataSource alloc]init];
tableDelegate = [[TableViewDelegate alloc]init];
//請求數據
[PersonalCenterService getPersonalCenterData:^(PersonalCenterModel * headModel,NSArray *sectionDataArray) {
self.headModel = headModel;
tableDataSource.dataArray = sectionDataArray;
tableDelegate.dataArray = sectionDataArray;
[self.tableView reloadData];
}];
複製代碼
通過以上三個步驟以後,Controller已經達到了瘦身的效果。但若是實際開發中業務邏輯太多、Controller仍然仍是很胖的。這種狀況咱們須要把Controller中的業務邏輯提取出到Prsenter類中、Controller專門負責UI展現、佈局,再也不關心業務操做。這裏採用的思想是在MVC基礎上擴展的MVP,咱們定義專門協議類,讓Prsenter類去實現,Controller只要跟Presenter交流就好
1.協議部分
#import <Foundation/Foundation.h>
#import "PersonalCenterModel.h"
NS_ASSUME_NONNULL_BEGIN
@protocol PersonalCenterProtocol <NSObject>
@optional
/***
定義協議、全部邏輯業務都讓Present類去處理、controller和view只負責UI佈局和數據顯示
**/
//註銷-prsenter實現
- (void)cancellation:(PersonalCenterModel*)model;
//刷新UI->tableView----->讓controller去實現(比較方便-爲了清晰、明瞭也能夠單獨給controller定義協議類)
- (void)reloadUI;
//點擊頭部-進入編輯頁面-prsenter實現
- (void)clickHead:(PersonalCenterModel*)model;
//cell點擊事件-進入詳情頁面並攜帶參數-prsenter實現
- (void)enterDetailPage:(personalSecontionModel*)model;
@end
NS_ASSUME_NONNULL_END
複製代碼
2.Prsenter處理
實現協議方法、處理業務邏輯。Prsenter就像箇中間人,從model獲取數據,通知view更新數據。model和view互相獨立。
#import "PresenterPesonalCenter.h"
#import "PersonalCenterViewController.h"
#import "PersonalCenterDeatilController.h"
@implementation PresenterPesonalCenter
//實現協議方法 註銷帳號&&點擊頭部進入想象
- (void)cancellation:(PersonalCenterModel*)model
{
PersonalCenterViewController *controller = (PersonalCenterViewController*)[self jsd_getCurrentViewController];
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"驗證信息" message:nil preferredStyle:UIAlertControllerStyleAlert];
// 添加文本框
[alertController addTextFieldWithConfigurationHandler:^(UITextField *textField){
textField.placeholder = @"請輸入姓名";
}];
[alertController addTextFieldWithConfigurationHandler:^(UITextField *textField){
textField.placeholder = @"請輸入身份證號碼";
}];
UIAlertAction * firstAction = [UIAlertAction actionWithTitle:@"肯定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action){
UITextField *name= alertController.textFields.firstObject;
UITextField *idCard= alertController.textFields.lastObject;
if ([NSString isEmptString:name.text]&&[NSString isEmptString:idCard.text]) {
[ASRequestHUD showErrorWithStatus:@"信息輸入不完整~"];
return ;
}
//網絡請求1-假設請求成功 處理業務
//網絡請求2-假設請求成功 處理業務
if ([NSString isEmptString:model.money]) {
[ASRequestHUD showErrorWithStatus:@"有餘額未體現,請提現後註銷"];
return;
}else if ([NSString isEmptString:model.blind])
{
[ASRequestHUD showErrorWithStatus:[NSString stringWithFormat:@"您還有%@張卡未解除,請前往解除綁定",model.blind]];
return;
}else if ([NSString isEmptString:model.cardCoupon])
{
[ASRequestHUD showErrorWithStatus:[NSString stringWithFormat:@"您還有%@張優惠卷未使用,請前往刪除或使用",model.cardCoupon]];
return;
}else
{
//網絡請求3-註銷-假設請求成功
//假設須要刷新數據
if (controller &&[controller respondsToSelector:@selector(reloadUI)]) {
[controller reloadUI];
}
}
}];
UIAlertAction *secondAction = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleDefault handler:nil];
[alertController addAction:firstAction];
[alertController addAction:secondAction];
[controller presentViewController:alertController animated:YES completion:nil];
}
- (void)clickHead:(PersonalCenterModel*)model
{
if ([model.grade isEqualToString:@"青銅"])
{
[ASRequestHUD showErrorWithStatus:@"您還不具有修改資格,努力升級吧"];
}else if ([model.grade isEqualToString:@"黃金"])
{
//邏輯處理
}else
{
//鑽石
}
}
- (void)enterDetailPage:(personalSecontionModel *)model
{
//進入詳情頁面
PersonalCenterDeatilController *controller = [PersonalCenterDeatilController new];
controller.title = model.title;
[[self jsd_getCurrentViewController].navigationController pushViewController:controller animated:YES];
}
複製代碼
3.controller處理
點擊事件中、指定讓presenter去實現就好
//頭部點擊事件
if (weakSelf.presenter&&[weakSelf.presenter respondsToSelector:@selector(clickHead:)]) {
[weakSelf.presenter clickHead:weakSelf.headModel];
}
//註銷點擊
if (self.presenter&&[self.presenter respondsToSelector:@selector(cancellation:)]) {
[self.presenter cancellation:self.headModel];
}
cell中點擊進入詳情
self.present = [[PresenterPesonalCenter alloc]init];
personalSecontionModel *model = self.dataArray[indexPath.section];
if (self.present&&[self.present respondsToSelector:@selector(enterDetailPage:)]) {
[self.present enterDetailPage:model];
}
複製代碼
1.經過以上處理、控制器溫柔一笑,自言自語道「我終於瘦下來了」,我要去照照鏡子了。
#import "PersonalCenterViewController.h"
#import "PersonalCenterView.h"
#import "PersonalCenterService.h"
#import "TableViewDataSource.h"
#import "TableViewDelegate.h"
#import "PresenterPesonalCenter.h"
@interface PersonalCenterViewController ()
{
TableViewDataSource *tableDataSource;
TableViewDelegate *tableDelegate;
}
@property(strong ,nonatomic)PresenterPesonalCenter *presenter;
@property(strong ,nonatomic)UITableView *tableView;
@property(strong ,nonatomic)PersonalCenterModel *headModel;
@property(strong,nonatomic)UIButton *footButton;
@end
@implementation PersonalCenterViewController
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
}
- (void)viewDidLoad {
[super viewDidLoad];
self.title = @"我的中心";
//初始化協議
tableDataSource = [[TableViewDataSource alloc]init];
tableDelegate = [[TableViewDelegate alloc]init];
//請求數據
[PersonalCenterService getPersonalCenterData:^(PersonalCenterModel * headModel,NSArray *sectionDataArray) {
self.headModel = headModel;
tableDataSource.dataArray = sectionDataArray;
tableDelegate.dataArray = sectionDataArray;
[self.tableView reloadData];
}];
//tableView
[self.view addSubview:self.tableView];
self.presenter = [[PresenterPesonalCenter alloc]init];
}
- (UITableView*)tableView
{
if (!_tableView) {
_tableView = [[UITableView alloc]initWithFrame:CGRectMake(0, KNavBarHeight, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height-KNavBarHeight) style:(UITableViewStyleGrouped)];
_tableView.dataSource = tableDataSource;
_tableView.delegate = tableDelegate;
_tableView.tableHeaderView = [self headView];
_tableView.tableFooterView = [self footView];
}
return _tableView;
}
- (UIView*)headView
{
WeakSelf;
PersonalCenterView *centerView = [[PersonalCenterView alloc]initWithFrame:CGRectMake(0, 0, kScreenWidth, 100) clickBlock:^{
//操做
if (weakSelf.presenter&&[weakSelf.presenter respondsToSelector:@selector(clickHead:)]) {
[weakSelf.presenter clickHead:weakSelf.headModel];
}
}];
centerView.model = self.headModel;
return centerView;
}
- (UIView*)footView
{
UIButton*(^creatButton)(NSString*,CGRect) = ^(NSString *title,CGRect frame)
{
UIButton *button = [[UIButton alloc] initWithFrame:frame];
button.backgroundColor = K_WhiteColor;
[button setTitle:title forState:UIControlStateNormal];
[button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[button addTarget:self action:@selector(cancellation) forControlEvents:UIControlEventTouchUpInside];
return button;
};
UIView *footView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, kScreenWidth, 100)];
footView.backgroundColor = [UIColor groupTableViewBackgroundColor];
UIButton *footbutton = creatButton(@"註銷",CGRectMake(0, 0, kScreenWidth, 50));
footbutton.center = footView.center;
[footView addSubview:footbutton];
return footView;
}
//註銷方法
- (void)cancellation
{
if (self.presenter&&[self.presenter respondsToSelector:@selector(cancellation:)]) {
[self.presenter cancellation:self.headModel];
}
}
#pragma mark-實現協議方法
- (void)reloadUI {
//假設需求須要清空數據-更新UI
tableDataSource.dataArray = @[];
[self.tableView reloadData];
}
- (void)dealloc
{
NSLog(@"控制器釋放了!!!!!!!!");
}
@end
複製代碼
2.Prsenter回之一笑,真是好女不過百也。方天下之英雄,爲使君與吾也。Controller發現再也不是本身一我的的天下了。
3.MVVM經過雙向綁定,也可使Controller達到瘦身效果。學習成本較前兩位高,也存在着缺點。我的認爲須要根據實際業務場景、不特別複雜的頁面,能用MVC就用MVC、代碼簡單、明瞭就好。最後附上結構圖。