最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

iOS架構從?MVC、MVP?到?MVVM

 更新時間:2023年03月24日 15:23:23   作者:九州編程  
這篇文章主要介紹了iOS架構從MVC、MVP到MVVM,文章關于MVC設計模式以及架構等均介紹的非常詳細,需要的朋友可以作為參考

概述

做了這么多年的客戶端研發(fā)一直在使用蘋果爸爸推薦的MVC架構模式。MVC從應用層面進行分層開發(fā),極大優(yōu)化了我們的代碼結構,簡單易上手,很容易被程序員所接受。程序員剛接手一個新項目,如果是MVC的架構模式,會減少代碼熟悉時間,快速的進行開發(fā)和維護工作,實際上對于多人開發(fā)維護的項目,MVC仍然是非常好的架構模式,這也是這種架構模式經久不衰的原因。
但是任何事物都有兩面性,隨著項目需求的增加,業(yè)務邏輯、網絡請求、代理方法等都往Controller層加塞,導致Controller層變得越來越臃腫,動輒上千行的代碼量絕對是維護人員的噩夢,因此在MVC基礎上逐漸衍生出來了MVP、MVVM等架構模式。
本文是基于OC代碼進行闡述的,使用iOS開發(fā)經典的 TableView 列表來分析每個架構模式。相信看了這篇文章你會有所領悟。當然一千個人眼中有一千種哈姆雷特,具體在業(yè)務開發(fā)中使用哪種模式需要你自己去衡量。

1.傳統(tǒng)的MVC設計模式

MVC
M: Model 數據層,負責網絡數據的處理,數據持久化存儲和讀取等工作
V: View 視圖層,負責呈現從數據層傳遞的數據渲染工作,以及與用戶的交互工作
C: Controller控制器,負責連接Model層跟View層,響應View的事件和作為View的代理,以及界面跳轉和生命周期的處理等任務

用戶的交互邏輯

用戶點擊 View(視圖) --> 視圖響應事件 -->通過代理傳遞事件到Controller–>發(fā)起網絡請求更新Model—>Model處理完數據–>代理或通知給Controller–>改變視圖樣式–>完成

可以看到Controller強引用View與Model,而View與Model是分離的,所以就可以保證Model和View的可測試性和復用性,但是Controller不行,因為Controller是Model和View的中介,所以不能復用,或者說很難復用。

iOS開發(fā)實際使用的MVC架構

在實際MVC在我們實際開發(fā)中使用的MVC模式可以看到,View與Controller耦合在一起了。這是由于每一個界面的創(chuàng)建都需要一個Controller,而每一個Controller里面必然會帶一個View,這就導致了C和V的耦合。這種結構確實可以提高開發(fā)效率,但是一旦界面復雜就會造成Controller變得非常臃腫和難以維護。

MVC代碼示例
我們要實現一個簡單的列表頁面,每行cell都一個按鈕,點擊按鈕前面數字?1操作

mvcexamp核心代碼:

// Controller
- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
    
    __weak typeof(self) wealSelf = self;
    MVCTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell_identifer"];
    if(cell == nil){
        cell = [[MVCTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Cell_identifer"];
    }
    DemoModel *model = self.dataArray[indexPath.row];
    [cell loadDataWithModel:model];
    cell.clickBtn = ^{
        NSLog(@"id===%ld",model.num);
        [wealSelf changeNumWithModel:model];
    };
    cell.selectionStyle = UITableViewCellSelectionStyleNone;
    return cell;
}
/*
* 用戶點擊事件通過Block傳遞過來后,在Controller層處理更新Mdoel以及更新視圖的邏輯
*/
- (void)changeNumWithModel:(DemoModel*)model{
    
    model.num++;
    NSIndexPath *path = [NSIndexPath indexPathForRow:model.Id inSection:0];
    [self.mainTabelView reloadRowsAtIndexPaths:@[path] withRowAnimation:UITableViewRowAnimationLeft];
}

可以看到用戶點擊事件通過Block傳遞過來后,在Controller層處理更新Mdoel以及更新視圖的邏輯

2.MVP設計模式

MVPM: Model 數據層,負責網絡數據的處理,數據持久化存儲和讀取等工作
V: View 視圖層,負責呈現從數據層傳遞的數據渲染工作,以及與用戶的交互,這里把Controller層也合并到視圖層
P: Presenter層,負責視圖需要數據的獲取,獲取到數據后刷新視圖。響應View的事件和作為View的代理。

可以看到 MVP模式跟原始的MVC模式非常相似,完全實現了View與Model層的分離,而且把業(yè)務邏輯放在了Presenter層中,視圖需要的所有數據都從Presenter獲取,而View與 Presenter通過協(xié)議進行事件的傳遞。

用戶的交互邏輯

用戶點擊 View(視圖) --> 視圖響應事件 -->通過代理傳遞事件到Presenter–>發(fā)起網絡請求更新Model–>Model處理完數據–>代理或通知給視圖(View或是Controller)–>改變視圖樣式–>完成

MVP代碼示例

項目結構

//DemoProtocal
import <Foundation/Foundation.h>


@protocol DemoProtocal <NSObject>
@optional
//用戶點擊按鈕 觸發(fā)事件: UI改變傳值到model數據改變  UI --- > Model 點擊cell 按鈕
-(void)didClickCellAddBtnWithIndexPathRow:(NSInteger)index;
//model數據改變傳值到UI界面刷新 Model --- > UI
-(void)reloadUI;
@end

我們把所有的代理抽象出來,成為一個Protocal文件。這兩個方法的作用:
-(void)didClickCellAddBtnWithIndexPathRow:(NSInteger)index;:Cell視圖調用它去Presenter層實現點擊邏輯的處理
-(void)reloadUI;: Presenter調用它去更新主視圖View或者Controller

//Presenter.h
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import "DemoProtocal.h"

NS_ASSUME_NONNULL_BEGIN

@interface Presenter : NSObject
@property (nonatomic, strong,readonly) NSMutableArray *dataArray;
@property (nonatomic, weak) id<DemoProtocal>delegate;//協(xié)議,去更新主視圖UI
// 更新 TableView UI 根據需求
- (void)requestDataAndUpdateUI;
//更新 cell UI
- (void)updateCell:(UITableViewCell*)cell withIndex:(NSInteger)index;
@end

dataArray : 視圖需要的數據源
- (void)requestDataAndUpdateUI;:主視圖Controller調用,去更新自己的UI
- (void)updateCell:(UITableViewCell*)cell withIndex:(NSInteger)index;:更新 Cell的UI

//Controller 層
- (void)iniData{
? ? self.presenter = [[Presenter alloc] init];
? ? self.presenter.delegate = self;
? ? [self.presenter requestDataAndUpdateUI];
}
...

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
? ? return self.presenter.dataArray.count;
}
- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
? ??
? ? MVPTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell_identifer"];
? ? if(cell == nil){
? ? ? ? cell = [[MVPTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Cell_identifer"];
? ? }
? ? //更新cell UI 數據
? ? [self.presenter updateCell:cell withIndex:indexPath.row];
? ? cell.selectionStyle = UITableViewCellSelectionStyleNone;
? ? return cell;
}

#pragma mark - DemoProtocal
//Presenter 的代理回調 數據更新了通知View去更新視圖
- (void)reloadUI{
? ? [self.mainTabelView reloadData];
}

Controller層初始化Presenter,調用其方法更新自己的UI,可以看到網絡數據的獲取,處理都在Presenter中,處理完成后通過協(xié)議回調給Controller去reload數據

//Cell
- (void)addBtnDown:(UIButton*)btn{
? ? NSLog(@"%s",__func__);
? ? if([self.delegate respondsToSelector:@selector(didClickCellAddBtnWithIndexPathRow:)]){
? ? ? ? [self.delegate didClickCellAddBtnWithIndexPathRow:self.index];
? ? }
}

Cell層點擊事件通過協(xié)議調用,而這個協(xié)議方法的實現是在Presenter中實現的。

MVP模式也有自身的缺點,所有的用戶操作和更新UI的回調需要定義,隨著交互越來越復雜,這些定義都要有很大一坨代碼。邏輯過于復雜的情況下,Present本身也會變得臃腫。所以衍生出了MVVM模式。

3.MVVM+RAC設計模式

MVVM
M: Model 數據層,負責網絡數據的處理,數據持久化存儲和讀取等工作
V: View 視圖層,此時的視圖層包括Controller,負責呈現從數據層傳遞的數據渲染工作,以及與用戶的交互
VM:ViewModel層,負責視圖需要數據的獲取,獲取到數據后刷新視圖。響應View的事件和作為View的代理等工作。
通過架構圖可以看到,MVVM模式跟MVP模式基本類似。主要區(qū)別是在MVP基礎上加入了雙向綁定機制。當被綁定對象某個值的變化時,綁定對象會自動感知,無需被綁定對象主動通知綁定對象??梢允褂肒VO和RAC實現。我們這里采用了RAC的實現方式。關于RAC如果不熟悉的小伙伴可以點這里,我們這篇文章不在涉及。

MVVM代碼示例

我們這里包括兩層視圖:主視圖Controller以及Cell,分別對應兩層ViewModel:ViewModel和CellViewModel

//ViewModel.h

@interface ViewModel : NSObject
//發(fā)送數據請求的Rac,可以去訂閱獲取 請求結果
@property (nonatomic,strong,readonly) RACCommand *requestCommand;
@property (nonatomic,strong) NSArray *dataArr;//返回子級對象的ViewModel
- (CellViewModel *)itemViewModelForIndex:(NSInteger)index;
@end

RACCommand *requestCommand:提供供主視圖調用的命令,調用它去獲取網絡數據
NSArray *dataArr: 提供供主視圖使用的數據源,注意這里不能用NSMutableArray,因為NSMutableArray不支持KVO,不能被RACObserve。
- (CellViewModel *)itemViewModelForIndex:(NSInteger)index; 根據Cell的index返回它需要的的ViewModel

@interface CellViewModel : NSObject

@property (nonatomic,copy,readonly) NSString *titleStr;

@property (nonatomic,copy,readonly) NSString *numStr;

@property (nonatomic,copy,readonly) RACCommand *addCommand;

- (instancetype)initWithModel:(DemoModel *)model;

@end

CellViewModel: 暴露出Cell渲染需要的所有數據
RACCommand *addCommand;: 按鈕點擊事件的指令,觸發(fā)后需要在CellViewModel里面做處理。

//controller
- (void)iniData{
? ? self.viewModel = [[ViewModel alloc] init];
? ? // 發(fā)送請求
? ? RACSignal *signal = [self.viewModel.requestCommand execute:@{@"page":@"1"}];
? ? [signal subscribeNext:^(id x) {
? ? ? ? NSLog(@"x=======%@",x);
? ? ? ? if([x boolValue] == 1){//請求成功
? ? ? ? ? ? [self.mainTabelView reloadData];
? ? ? ? }
? ? }];
}
- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
? ??
? ? MVVMTableVIewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell_identifer"];
? ? if(cell == nil){
? ? ? ? cell = [[MVVMTableVIewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Cell_identifer"];
? ? }
? ? //更新cell UI 數據
? ? cell.cellViewModel = [self.viewModel itemViewModelForIndex:indexPath.row];
? ? cell.selectionStyle = UITableViewCellSelectionStyleNone;
? ? ? ??
? ? return cell;
}

iniData:初始化ViewModel,并發(fā)送請求命令。這里可以監(jiān)聽這個完成信號,進行刷新視圖操作
cell.cellViewModel = [self.viewModel itemViewModelForIndex:indexPath.row]; 根據主視圖的ViewModel去獲取Cell的ViewModel,實現cell的數據綁定。

//TableViewCell

? ? RAC(self.titleLabel,text) = RACObserve(self, cellViewModel.titleStr);
? ? RAC(self.numLabel,text) = RACObserve(self, cellViewModel.numStr);

? ? [[self.addBtn rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(id x) {
? ? ? ? NSLog(@">>>>>");
? ? ? ? [self.cellViewModel.addCommand execute:nil];
? ? }];

在Cell里面進行與ViewModel的數據綁定,這邊有個注意Racobserve左邊只有self右邊才有viewModel.titleStr這樣就避Cell重用的問題。
[self.cellViewModel.addCommand execute:nil];:按鈕的點擊方法觸發(fā),事件的處理在CellViewModel中。

總結

到此這篇關于iOS架構從 MVC、MVP 到 MVVM的文章就介紹到這了,更多相關淺談MVC的內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!。

相關文章

最新評論

田阳县| 夹江县| 阿拉善左旗| 景宁| 贡觉县| 玉山县| 商河县| 岳阳县| 大邑县| 罗甸县| 上思县| 新宁县| 维西| 名山县| 康定县| 伊宁县| 平谷区| 平遥县| 富锦市| 灯塔市| 高雄县| 雷山县| 灵宝市| 呼和浩特市| 八宿县| 临海市| 南宫市| 瑞丽市| 永嘉县| 和林格尔县| 武定县| 宜章县| 北京市| 永州市| 阜平县| 益阳市| 台南市| 涪陵区| 额济纳旗| 五指山市| 兴隆县|