iOS中的幾種常用架構
MVC
MVC架構是以Model、Controller、View三者之間的關系來依賴的
Apple版的MVC
Apple最早的MVC的數(shù)據(jù)流向是以Controller為中心,在Model和View中間作為橋梁來銜接,而且Controller和Model、View之間的數(shù)據(jù)流向都是雙向的

例如,View上通過按鈕的點擊傳遞給Controller,Controller就去獲取數(shù)據(jù)來作為Model;Model的數(shù)據(jù)有了改變,又要通過展示到Controller展示到View上
三者的交互過程中,View和Model是互相沒有直接關聯(lián)的
在iOS程序中最常見的就是tableview的展示,見示例代碼
// LLNews
@interface LLNews : NSObject
@property (copy, nonatomic) NSString *title;
@property (copy, nonatomic) NSString *content;
@end
@implementation LLNews
@end
// LLNewsViewController
@interface LLNewsViewController : UITableViewController
@end
@interface LLNewsViewController ()
@property (strong, nonatomic) NSMutableArray *newsData;
@end
@implementation LLNewsViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self loadNewsData];
}
- (void)loadNewsData
{
self.newsData = [NSMutableArray array];
for (int i = 0; i < 20; i++) {
LLNews *news = [[LLNews alloc] init];
news.title = [NSString stringWithFormat:@"news-title-%d", i];
news.content = [NSString stringWithFormat:@"news-content-%d", i];
[self.newsData addObject:news];
}
}
#pragma mark - Table view data source
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.newsData.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"NewsCell" forIndexPath:indexPath];
LLNews *news = self.newsData[indexPath.row];
cell.detailTextLabel.text = news.title;
cell.textLabel.text = news.content;
return cell;
}
#pragma mark - UITableViewDelegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(@"1111");
}
@end
優(yōu)點:tableView和newsData都是相對獨立的,可以復用
缺點:大量的賦值代碼會寫在Controller中,Controller變得過于臃腫
變種的MVC
變種后的MVC的數(shù)據(jù)流向,Controller和View還是相互作用的,Controller也還是會去獲取數(shù)據(jù)來作為Model;不同的是View也可以直接持有Model了,三者之間互相都有了交互

下面我們用示例代碼來說明三者之間的具體關系
// LLApp
@interface LLApp : NSObject
@property (copy, nonatomic) NSString *name;
@property (copy, nonatomic) NSString *image;
@end
@implementation LLApp
@end
// LLAppView
@class LLApp, LLAppView;
@protocol LLAppViewDelegate <NSObject>
@optional
- (void)appViewDidClick:(LLAppView *)appView;
@end
@interface LLAppView : UIView
@property (strong, nonatomic) LLApp *app;
@property (weak, nonatomic) id<LLAppViewDelegate> delegate;
@end
@interface LLAppView()
@property (weak, nonatomic) UIImageView *iconView;
@property (weak, nonatomic) UILabel *nameLabel;
@end
@implementation LLAppView
- (instancetype)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
UIImageView *iconView = [[UIImageView alloc] init];
iconView.frame = CGRectMake(0, 0, 100, 100);
[self addSubview:iconView];
_iconView = iconView;
UILabel *nameLabel = [[UILabel alloc] init];
nameLabel.frame = CGRectMake(0, 100, 100, 30);
nameLabel.textAlignment = NSTextAlignmentCenter;
[self addSubview:nameLabel];
_nameLabel = nameLabel;
}
return self;
}
- (void)setApp:(LLApp *)app
{
_app = app;
self.iconView.image = [UIImage imageNamed:app.image];
self.nameLabel.text = app.name;
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
if ([self.delegate respondsToSelector:@selector(appViewDidClick:)]) {
[self.delegate appViewDidClick:self];
}
}
@end
// ViewController
@interface ViewController () <LLAppViewDelegate>
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// 創(chuàng)建view
LLAppView *appView = [[LLAppView alloc] init];
appView.frame = CGRectMake(100, 100, 100, 150);
appView.delegate = self;
[self.view addSubview:appView];
// 加載模型數(shù)據(jù)
LLApp *app = [[LLApp alloc] init];
app.name = @"QQ";
app.image = @"QQ";
// 設置數(shù)據(jù)到view上
appView.app = app;
}
#pragma mark - LLAppViewDelegate
- (void)appViewDidClick:(LLAppView *)appView
{
NSLog(@"控制器監(jiān)聽到了appView的點擊");
}
@end
優(yōu)點:Controller會相對減負,減少View的數(shù)據(jù)賦值代碼,而且外部不用關心View的屬性以及做了什么
缺點:View和Model耦合性太高了,會造成相互依賴,不能再分別單獨使用了,復用性降低了
MVP
MVP架構是以Model、Presenter、View三者之間的關系來依賴的
Presenter更像是替代了Controller來作為Model和View之間的橋梁,而Controller只需要管理Presenter就可以了

我們借由上面的示例來做下調整,示例代碼如下
LLApp和LLAppView基本不變
// LLApp
@interface LLApp : NSObject
@property (copy, nonatomic) NSString *name;
@property (copy, nonatomic) NSString *image;
@end
@implementation LLApp
@end
// LLAppView
@class LLAppView;
@protocol LLAppViewDelegate <NSObject>
@optional
- (void)appViewDidClick:(LLAppView *)appView;
@end
@interface LLAppView : UIView
- (void)setName:(NSString *)name andImage:(NSString *)image;
@property (weak, nonatomic) id<LLAppViewDelegate> delegate;
@end
@interface LLAppView()
@property (weak, nonatomic) UIImageView *iconView;
@property (weak, nonatomic) UILabel *nameLabel;
@end
@implementation LLAppView
- (instancetype)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
UIImageView *iconView = [[UIImageView alloc] init];
iconView.frame = CGRectMake(0, 0, 100, 100);
[self addSubview:iconView];
_iconView = iconView;
UILabel *nameLabel = [[UILabel alloc] init];
nameLabel.frame = CGRectMake(0, 100, 100, 30);
nameLabel.textAlignment = NSTextAlignmentCenter;
[self addSubview:nameLabel];
_nameLabel = nameLabel;
}
return self;
}
- (void)setName:(NSString *)name andImage:(NSString *)image
{
_iconView.image = [UIImage imageNamed:image];
_nameLabel.text = name;
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
if ([self.delegate respondsToSelector:@selector(appViewDidClick:)]) {
[self.delegate appViewDidClick:self];
}
}
@end
多出來的Presenter和抽取后的Controller代碼如下
// LLAppPresenter
@interface LLAppPresenter : NSObject
- (instancetype)initWithController:(UIViewController *)controller;
@end
@interface LLAppPresenter() <LLAppViewDelegate>
@property (weak, nonatomic) UIViewController *controller;
@end
@implementation LLAppPresenter
- (instancetype)initWithController:(UIViewController *)controller
{
if (self = [super init]) {
self.controller = controller;
// 創(chuàng)建View
LLAppView *appView = [[LLAppView alloc] init];
appView.frame = CGRectMake(100, 100, 100, 150);
appView.delegate = self;
[controller.view addSubview:appView];
// 加載模型數(shù)據(jù)
LLApp *app = [[LLApp alloc] init];
app.name = @"QQ";
app.image = @"QQ";
// 賦值數(shù)據(jù)
[appView setName:app.name andImage:app.image];
}
return self;
}
#pragma mark - MJAppViewDelegate
- (void)appViewDidClick:(LLAppView *)appView
{
NSLog(@"presenter 監(jiān)聽了 appView 的點擊");
}
@end
// ViewController
@interface ViewController ()
@property (strong, nonatomic) LLAppPresenter *presenter;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.presenter = [[LLAppPresenter alloc] initWithController:self];
}
@end
優(yōu)點:
- 每個
Presenter對應著各自的Model和View
Model和View也更加的獨立性、可復用
Controller里變得更簡潔,只需要管理不同的Presenter就可以
MVVM
MVVM架構是以Model、ViewModel、View三者之間的關系來依賴的,其中的View包括了View和Controller
ViewModel的作用是將Controller的業(yè)務邏輯抽取出來,并且把Model和View做一個綁定關系

我們將MVC的tableview的示例做了更改后,代碼如下
// LLNews
@interface LLNews : NSObject
@property (copy, nonatomic) NSString *title;
@property (copy, nonatomic) NSString *content;
@end
@implementation LLNews
@end
// LLNewsViewModel
@interface LLNewsViewModel : NSObject
- (void)loadNewsData:(void (^)(NSArray *newsData))completion;
@end
@implementation LLNewsViewModel
- (void)loadNewsData:(void (^)(NSArray *))completion
{
if (!completion) return;
NSMutableArray *newsData = [NSMutableArray array];
for (int i = 0; i < 20; i++) {
// 發(fā)送網(wǎng)絡請求、字典轉模型
LLNews *news = [[LLNews alloc] init];
news.title = [NSString stringWithFormat:@"news-title-%d", i];
news.content = [NSString stringWithFormat:@"news-content-%d", i];
[newsData addObject:news];
}
completion(newsData);
}
@end
// LLNewsViewController
@interface LLNewsViewController ()
@property (nonatomic, strong) LLNewsViewModel *newsVM;
@property (nonatomic, assign) NSArray *newsData;
@end
@implementation LLNewsViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.newsVM = [[LLNewsViewModel alloc] init];
[self.newsVM loadNewsData:^(NSArray *newsData) {
self.newsData = newsData;
}];
}
#pragma mark - Table view data source
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.newsData.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"NewsCell" forIndexPath:indexPath];
LLNews *news = self.newsData[indexPath.row];
cell.detailTextLabel.text = news.title;
cell.textLabel.text = news.content;
return cell;
}
#pragma mark - UITableViewDelegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(@"1111");
}
@end
優(yōu)點:Controller可以不用寫邏輯代碼,相對減輕負擔,MVVM可以結合一些響應式框架來更簡便使用
架構分層
一般我們經(jīng)常會分為三層架構,分別是界面層、業(yè)務層、數(shù)據(jù)層
MVC、MVP、MVVM這幾種架構都是建立于界面層來討論的
架構分層的目的就是為了降低耦合性,易于維護和開發(fā)
設計模式
什么是設計模式
設計模式(Design Pattern)是一套被反復使用、代碼設計經(jīng)驗的總結
使用設計模式的好處是:可重用代碼、讓代碼更容易被他人理解、保證代碼可靠性
一般與編程語言無關,是一套比較成熟的編程思想### 設計模式的幾大類設計模式可以分為三大類- 創(chuàng)建型模式:對象實例化的模式,用于解耦對象的實例化過程 - 單例模式、工廠方法模式,等等- 結構型模式:把類或對象結合在一起形成一個更大的結構 - 代理模式、適配器模式、組合模式、裝飾模式,等等- 行為型模式:類或對象之間如何交互,及劃分責任和算法 - 觀察者模式、命令模式、責任鏈模式,等等具體概述之后再詳細討論
|