一、MVC闡述
1.MVC(Model、View污淋、Controller),即模型骑疆、視圖田篇、控制器;
Model:
模型對象封裝了應用程序的數(shù)據(jù)箍铭,并定義操控和處理該數(shù)據(jù)的邏輯和運算泊柬。例如,模型對象可能是表示商品數(shù)據(jù) list诈火。用戶在視圖層中所進行的創(chuàng)建或修改數(shù)據(jù)的操作兽赁,通過控制器對象傳達出去,最終會創(chuàng)建或更新模型對象柄瑰。模型對象更改時(例如通過網(wǎng)絡連接接收到新數(shù)據(jù)),它通知控制器對象剪况,控制器對象更新相應的視圖對象教沾。View:
視圖對象是應用程序中用戶可以看見的對象。視圖對象知道如何將自己繪制出來译断,可能對用戶的操作作出響應授翻。視圖對象的主要目的就是顯示來自應用程序模型對象的數(shù)據(jù),并使該數(shù)據(jù)可被編輯孙咪。盡管如此堪唐,在 MVC 應用程序中,視圖對象通常與模型對象分離翎蹈。Controller:
在應用程序的一個或多個視圖對象和一個或多個模型對象之間淮菠,控制器對象充當媒介』缈埃控制器對象因此是同步管道程序合陵,通過它,視圖對象了解模型對象的更改澄阳,反之亦然拥知。控制器對象還可以為應用程序執(zhí)行設置和協(xié)調任務碎赢,并管理其他對象的生命周期低剔。
控制器對象解釋在視圖對象中進行的用戶操作,并將新的或更改過的數(shù)據(jù)傳達給模型對象肮塞。模型對象更改時襟齿,一個控制器對象會將新的模型數(shù)據(jù)傳達給視圖對象,以便視圖對象可以顯示它枕赵。
2.實例描述
- 比如在iOS程序中蕊唐,視圖、按鈕烁设、彈框等都對應View替梨,承載數(shù)據(jù)特征或數(shù)據(jù)處理邏輯的Object對應Model钓试,通常一個頁面下會用到多個View和Model,如根據(jù)條件展示不同的彈框副瀑,這個時候就需要一個管理者來管理他們弓熏,也就是需要一個控制器,那么iOS中的ViewController就對應上面所說的Controller糠睡。
就比如畫畫一樣挽鞠,有模特、畫師狈孔、畫板
需要展現(xiàn)的是模特的身材信认、樣貌、氣質等特征均抽,那么模特就對應Model嫁赏,他封裝了要展示的數(shù)據(jù);
畫板需要將模特的身材油挥、樣貌潦蝇、氣質等特征呈現(xiàn)出來,對應View深寥;
而畫師則負責在兩者之間做傳遞攘乒,畫師需要將自己所看到的模特的樣子畫在畫板上,如果模特換了個姿勢惋鹅,換了套衣服则酝,會影響畫師去調整或更換畫板,同時畫板的成像效果也會影響到畫師來通知模特做些調整闰集,比如保持微笑等,堤魁,畫師對應Controller
3.MVC 的幾個明顯的特征和體現(xiàn):
- View上展示什么東西取決于Model
- 只要 Model 數(shù)據(jù)改了,View 的顯示狀態(tài)會跟著更改
- Controller 負責初始化 Model和VIew返十,并將 Model 傳遞給 View 去解析展示
4.簡單的 MVC
- 控制器加載模型數(shù)據(jù)并將數(shù)據(jù)轉換為數(shù)據(jù)模型妥泉。
- 控制器創(chuàng)建視圖控件,并將模型數(shù)據(jù)傳遞給視圖控件
二洞坑、iOS中的標準MVC
1.比如iOS中的如下例子
- 創(chuàng)建一個TestView
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface TestView : UIView
@property (nonatomic, strong) UILabel *nameLb;
@end
NS_ASSUME_NONNULL_END
#import "TestView.h"
@implementation TestView
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self addSubview:self.nameLb];
}
return self;
}
- (UILabel*)nameLb
{
if (!_nameLb) {
_nameLb = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 80, 30)];
_nameLb.center = self.center;
_nameLb.textAlignment = NSTextAlignmentCenter;
}
return _nameLb;
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect {
// Drawing code
}
*/
@end
- 創(chuàng)建一個Model
#import <Foundation/Foundation.h>
@interface ZYModel : NSObject
@property (nonatomic, copy) NSString *name;
@end
#import "ZYModel.h"
@implementation ZYModel
@end
- 創(chuàng)建一個Controller
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
@end
#import "ViewController.h"
#import "ZYModel.h"
#import "TestView.h"
@interface ViewController ()
@property (nonatomic, strong) ZYModel *zyModel;
@property (nonatomic, strong) TestView *testView;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self loadData];
[self initTestView];
}
- (void)loadData
{
self.zyModel = [[ZYModel alloc] init];
self.zyModel.name = @"趙揚揚";
}
- (void)initTestView
{
self.testView = [[TestView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
self.testView.center = self.view.center;
self.testView.nameLb.text = self.zyModel.name;
[self.view addSubview:self.testView];
}
@end
由上圖的例子可以看出盲链,控制器加載模型數(shù)據(jù)并將數(shù)據(jù)轉換為數(shù)據(jù)模型〕僭樱控制器創(chuàng)建視圖控件刽沾,并將模型數(shù)據(jù)傳遞給視圖控件
但在實際應用過程中,由于不可避免的交互排拷,數(shù)據(jù)和界面都會出現(xiàn)更新侧漓,因此就會產(chǎn)生通信,在iOS中监氢,MVC模式的通信關系如下圖所示
Model 和 View 永遠不能相互通信布蔗,只能通過 Controller 傳遞藤违。
Controller 可以直接與 Model 對話(讀寫調用 Model),Model 通過 Notification 和 KVO 等機制與 Controller 間接通信纵揍。
Controller 可以直接與 View 對話顿乒,通過 outlet,直接操作 View泽谨,outlet 直接對應到 View 中的控件璧榄,View 通過 action 向 Controller 報告事件的發(fā)生(如用戶 Touch 我了)。Controller 是 View 的直接數(shù)據(jù)源(數(shù)據(jù)很可能是 Controller 從 Model 中取得并經(jīng)過加工了)吧雹。Controller 是 View 的代理(delegate)骨杂,以同步 View 與 Controller。
比如在上面的iOS例子中雄卷,如果ZYModel中的name屬性改變了搓蚪,由趙揚揚變成了揚揚,那么TestView上就不能再展示為趙揚揚了龙亲,要變成揚揚陕凹,這個流程如下:ZYModel通過一種方式告知ViewCotroller我的name改變了悍抑,然后由ViewCotroller去告知TestView去更新展示鳄炉,同樣的道理,如果是TestView由于用戶的交互要改變ZYModel的name搜骡,也是通過ViewCotroller去傳達拂盯。如下圖
三、MVC變種
在上面的例子中记靡,ZYModel只有一個屬性谈竿,TestView也只有一個nameLb屬性,控制器傳值的時候是將ZYModel的對象數(shù)據(jù)傳給TestView的對應屬性或控件摸吠,但如果ZYModel和TestView都擁有多個屬性空凸,那么按照上面所說的模式則只能一一對應傳值,而且TestView需要將它需要更新的屬性全部暴露出來寸痢!
@interface TestView : UIView
@property (nonatomic, strong) UILabel *nameLb;
@property (nonatomic, strong) UILabel *ageLb;
@property (nonatomic, strong) UILabel *sexLb;
@end
@interface ZYModel : NSObject
@property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) NSString *age;
@property (nonatomic, copy) NSString *sex;
@end
在VIewController中將這些傳值
self.testView.nameLb.text = self.zyModel.name;
self.testView.ageLb.text = self.zyModel.age;
self.testView.sexLb.text = self.zyModel.sex;
由上面的例子可以看出呀洲,如果屬性很多、模型也不知一個啼止,這樣一來Controller中的代碼會非常臃腫道逗,所以通常我們開發(fā)中會做一些改動,讓View依賴于Model献烦,將View內部的細節(jié)封裝起來滓窍!如下圖所示
相對于標準的MVC,變種過的MVC中由于View依賴于Model巩那,所以View的獨立性和可復用性不如標準MVC中的View高
但變種MVC的控制器代碼更精簡一些吏夯,View的封裝性更好一些此蜈。
總結
在實際開發(fā)中,如果采用MVC模式锦亦,往往會造成控制器比較臃腫舶替,因為往往一個控制器需要承載和管理多個View和Model,再者杠园,這幾層之間耦合比較嚴重顾瞪,不利于大型項目的維護,其靈活性也比較差抛蚁。在實際應用中陈醒,應盡量給控制器瘦身、抽離業(yè)務邏輯瞧甩。以免代碼臃腫钉跷、耦合嚴重!