亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

iOS架構從MVC、MVP到MVVM源碼分析

發布時間:2023-03-25 17:27:33 來源:億速云 閱讀:95 作者:iii 欄目:開發技術

本篇內容主要講解“iOS架構從MVC、MVP到MVVM源碼分析”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“iOS架構從MVC、MVP到MVVM源碼分析”吧!

1.傳統的MVC設計模式

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

用戶的交互邏輯

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

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

iOS開發實際使用的MVC架構

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

MVC代碼示例

我們要實現一個簡單的列表頁面,每行cell都一個按鈕,點擊按鈕前面數字iOS架構從MVC、MVP到MVVM源碼分析1操作。
iOS架構從MVC、MVP到MVVM源碼分析

核心代碼:

// 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設計模式

iOS架構從MVC、MVP到MVVM源碼分析

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

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

用戶的交互邏輯

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

MVP代碼示例

iOS架構從MVC、MVP到MVVM源碼分析

//DemoProtocal
import <Foundation/Foundation.h>

@protocol DemoProtocal <NSObject>
@optional
//用戶點擊按鈕 觸發事件: 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;//協議,去更新主視圖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中,處理完成后通過協議回調給Controller去reload數據

//Cell
- (void)addBtnDown:(UIButton*)btn{
    NSLog(@"%s",__func__);
    if([self.delegate respondsToSelector:@selector(didClickCellAddBtnWithIndexPathRow:)]){
        [self.delegate didClickCellAddBtnWithIndexPathRow:self.index];
    }
}
  • Cell層點擊事件通過協議調用,而這個協議方法的實現是在Presenter中實現的。

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

3.MVVM+RAC設計模式

iOS架構從MVC、MVP到MVVM源碼分析
M: Model 數據層,負責網絡數據的處理,數據持久化存儲和讀取等工作
V: View 視圖層,此時的視圖層包括Controller,負責呈現從數據層傳遞的數據渲染工作,以及與用戶的交互
VM:ViewModel層,負責視圖需要數據的獲取,獲取到數據后刷新視圖。響應View的事件和作為View的代理等工作。
通過架構圖可以看到,MVVM模式跟MVP模式基本類似。主要區別是在MVP基礎上加入了雙向綁定機制。當被綁定對象某個值的變化時,綁定對象會自動感知,無需被綁定對象主動通知綁定對象。可以使用KVO和RAC實現。我們這里采用了RAC的實現方式。

MVVM代碼示例

iOS架構從MVC、MVP到MVVM源碼分析

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

//ViewModel.h

@interface ViewModel : NSObject
//發送數據請求的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;: 按鈕點擊事件的指令,觸發后需要在CellViewModel里面做處理。

//controller
- (void)iniData{
    self.viewModel = [[ViewModel alloc] init];
    // 發送請求
    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,并發送請求命令。這里可以監聽這個完成信號,進行刷新視圖操作

  • 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];:按鈕的點擊方法觸發,事件的處理在CellViewModel中。

到此,相信大家對“iOS架構從MVC、MVP到MVVM源碼分析”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

昆明市| 监利县| 都江堰市| 桂林市| 永济市| 洪江市| 子洲县| 喀喇沁旗| 浦城县| 华容县| 灵山县| 吴堡县| 西乌| 江阴市| 和龙市| 余干县| 建昌县| 河西区| 乌苏市| 成都市| 宁远县| 临猗县| 镇雄县| 樟树市| 镇康县| 内黄县| 克拉玛依市| 克山县| 光泽县| 大姚县| 三江| 松原市| 宜黄县| 兖州市| 金川县| 白河县| 福泉市| 白玉县| 肥西县| 赣州市| 神池县|