MVC - Apple
控制器作為
Model
和View
中間的協(xié)調(diào)者玄渗,Model負(fù)責(zé)數(shù)據(jù)記錄妻顶,View負(fù)責(zé)試圖条霜,而在控制器中創(chuàng)建View蛾绎,給View賦值Model數(shù)據(jù)薄啥,協(xié)調(diào)雙方以TableView為栗子:
#import "TableViewController1.h"
#import "MJModel.h"
@interface TableViewController1 ()
@property (nonatomic,strong)NSMutableArray *datas;
@end
@implementation TableViewController1
- (void)viewDidLoad {
[super viewDidLoad];
self.datas = [NSMutableArray array];
for (int i = 0; i < 20; i++ ) {
MJModel *model = [[MJModel alloc] init];
model.title = [NSString stringWithFormat:@"title --- %d",i];
model.detail_title = [NSString stringWithFormat:@"detail_title --- %d",i];
[self.datas addObject:model];
}
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Table view data source
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
#warning Incomplete implementation, return the number of rows
return self.datas.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"MJCell" forIndexPath:indexPath];
MJModel *model = self.datas[indexPath.row];
cell.textLabel.text = model.title;
cell.detailTextLabel.text = model.detail_title;
return cell;
}
@end
這里撩扒,控制器協(xié)調(diào)View和Model似扔,最終展示TableVIew
Apple的MVC的好處就是Model和View耦合性低,但是控制器的代碼臃腫
MVC - 變種
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
MJCell *cell = [tableView dequeueReusableCellWithIdentifier:@"MJCell" forIndexPath:indexPath];
MJModel *model = self.datas[indexPath.row];
cell.model = model;
// cell.textLabel.text = model.title;
// cell.detailTextLabel.text = model.detail_title;
//
return cell;
}
#import <UIKit/UIKit.h>
#import "MJModel.h"
@interface MJCell : UITableViewCell
@property (nonatomic,strong)MJModel *model;
@end
#import "MJCell.h"
@implementation MJCell
- (void)awakeFromNib {
[super awakeFromNib];
// Initialization code
}
- (void)setModel:(MJModel *)model {
_model = model;
self.textLabel.text = model.title;
self.detailTextLabel.text = model.detail_title;
}
@end
MVC的變種使控制器代碼變得簡單一點,但是增加了View和控制器的關(guān)系,View依賴與Model的結(jié)構(gòu)
MVP
類似于Apple的MVC撮竿,只是把讓
presenter
擁有控制器,并把業(yè)務(wù)邏輯寫到presenter
里這里辆脸,控制器加載
presenter
#import "ViewController.h"
#import "MJAppPresenter.h"
@interface ViewController ()
@property (strong, nonatomic) MJAppPresenter *presenter;
//@property (strong, nonatomic) MJOtherPresenter *presenter1;
//@property (strong, nonatomic) MJNewsPresenter *presenter2;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.presenter = [[MJAppPresenter alloc] initWithController:self];
}
@end
Presenter實現(xiàn):
#import "MJAppPresenter.h"
#import "MJApp.h"
#import "MJAppView.h"
@interface MJAppPresenter() <MJAppViewDelegate>
@property (weak, nonatomic) UIViewController *controller;
@end
@implementation MJAppPresenter
- (instancetype)initWithController:(UIViewController *)controller
{
if (self = [super init]) {
self.controller = controller;
// 創(chuàng)建View
MJAppView *appView = [[MJAppView alloc] init];
appView.frame = CGRectMake(100, 100, 100, 150);
appView.delegate = self;
[controller.view addSubview:appView];
// 加載模型數(shù)據(jù)
MJApp *app = [[MJApp alloc] init];
app.name = @"QQ";
app.image = @"QQ";
// 賦值數(shù)據(jù)
[appView setName:app.name andImage:app.image];
// appView.iconView.image = [UIImage imageNamed:app.image];
// appView.nameLabel.text = app.name;
}
return self;
}
#pragma mark - MJAppViewDelegate
- (void)appViewDidClick:(MJAppView *)appView
{
NSLog(@"presenter 監(jiān)聽了 appView 的點擊");
}
@end
View 聲明
@class MJAppView;
@protocol MJAppViewDelegate <NSObject>
@optional
- (void)appViewDidClick:(MJAppView *)appView;
@end
@interface MJAppView : UIView
- (void)setName:(NSString *)name andImage:(NSString *)image;
@property (weak, nonatomic) id<MJAppViewDelegate> delegate;
@end
View 實現(xiàn)
#import "MJAppView.h"
@interface MJAppView()
@property (weak, nonatomic) UIImageView *iconView;
@property (weak, nonatomic) UILabel *nameLabel;
@end
@implementation MJAppView
- (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
MVVM
MVVM 與MVP類似,用ViewModel代替了Presenter螃诅,而MVVM的核心在于讓View和ViewModel雙向綁定啡氢,讓View監(jiān)聽ViewModel的屬性改變状囱,以實現(xiàn)視圖更新
ViewModel:
#import "MJAppViewModel.h"
#import "MJApp.h"
#import "MJAppView.h"
@interface MJAppViewModel() <MJAppViewDelegate>
@property (weak, nonatomic) UIViewController *controller;
@property (copy, nonatomic) NSString *name;
@property (copy, nonatomic) NSString *image;
@end
@implementation MJAppViewModel
- (instancetype)initWithController:(UIViewController *)controller
{
if (self = [super init]) {
self.controller = controller;
// 創(chuàng)建View
MJAppView *appView = [[MJAppView alloc] init];
appView.frame = CGRectMake(100, 100, 100, 150);
appView.delegate = self;
appView.viewModel = self; // 讓View持有ViewModel
[controller.view addSubview:appView];
// 加載模型數(shù)據(jù)
MJApp *app = [[MJApp alloc] init];
app.name = @"QQ";
app.image = @"QQ";
// 設(shè)置數(shù)據(jù)
self.name = app.name;
self.image = app.image;
}
return self;
}
#pragma mark - MJAppViewDelegate
- (void)appViewDidClick:(MJAppView *)appView
{
NSLog(@"viewModel 監(jiān)聽了 appView 的點擊");
}
@end
VIew:
#import <UIKit/UIKit.h>
@class MJAppView, MJAppViewModel;
@protocol MJAppViewDelegate <NSObject>
@optional
- (void)appViewDidClick:(MJAppView *)appView;
@end
@interface MJAppView : UIView
@property (weak, nonatomic) MJAppViewModel *viewModel;
@property (weak, nonatomic) id<MJAppViewDelegate> delegate;
@end
#import "MJAppView.h"
#import "NSObject+FBKVOController.h"
@interface MJAppView()
@property (weak, nonatomic) UIImageView *iconView;
@property (weak, nonatomic) UILabel *nameLabel;
@end
@implementation MJAppView
- (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)setViewModel:(MJAppViewModel *)viewModel
{
_viewModel = viewModel;
// 監(jiān)聽ViewModel屬性改變 這里使用了一個第三方faceBook 的KVO
__weak typeof(self) waekSelf = self;
[self.KVOController observe:viewModel keyPath:@"name" options:NSKeyValueObservingOptionNew block:^(id _Nullable observer, id _Nonnull object, NSDictionary<NSKeyValueChangeKey,id> * _Nonnull change) {
waekSelf.nameLabel.text = change[NSKeyValueChangeNewKey];
}];
[self.KVOController observe:viewModel keyPath:@"image" options:NSKeyValueObservingOptionNew block:^(id _Nullable observer, id _Nonnull object, NSDictionary<NSKeyValueChangeKey,id> * _Nonnull change) {
waekSelf.iconView.image = [UIImage imageNamed:change[NSKeyValueChangeNewKey]];
}];
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
if ([self.delegate respondsToSelector:@selector(appViewDidClick:)]) {
[self.delegate appViewDidClick:self];
}
}
@end
分層架構(gòu)
三層架構(gòu)
四層架構(gòu)
Controller
#import "ViewController.h"
#import "MJNewsService.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[MJNewsService loadNews:@{} success:^(NSArray *newsData) {
} failure:^(NSError *error) {
}];
}
@end
Service
#import <Foundation/Foundation.h>
@interface MJNewsService : NSObject
+ (void)loadNews:(NSDictionary *)params success:(void (^)(NSArray *newsData))success failure:(void (^)(NSError *error))failure;
@end
#import "MJNewsService.h"
#import "MJHTTPTool.h"
#import "MJDBTool.h"
@implementation MJNewsService
+ (void)loadNews:(NSDictionary *)params success:(void (^)(NSArray *newsData))success failure:(void (^)(NSError *error))failure
{
// 先取出本地數(shù)據(jù)
// [MJDBTool loadLocalData....];
// 如果沒有本地數(shù)據(jù),就加載網(wǎng)絡(luò)數(shù)據(jù)
// [MJHTTPTool GET:@"xxxx" params:nil success:^(id result) {
// success(array);
// } failure:failure];
}
@end
Data
#import <Foundation/Foundation.h>
@interface MJHTTPTool : NSObject
+ (void)GET:(NSString *)URL params:(NSDictionary *)params success:(void (^)(id result))success failure:(void (^)(NSError *error))failure;
@end
#import "MJHTTPTool.h"
@implementation MJHTTPTool
+ (void)GET:(NSString *)URL params:(NSDictionary *)params success:(void (^)(id))success failure:(void (^)(NSError *))failure
{
// 調(diào)用AFN
}
@end
設(shè)計模式
推薦: