iOS底層day12 - 架構(gòu)設(shè)計

MVC - Apple

MVC-apple

控制器作為ModelView中間的協(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 - 變種

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

image.png

類似于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

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)


image.png

四層架構(gòu)


image.png

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è)計模式

image.png

推薦:


image.png
到這里倘是,就全部告一段落啦亭枷,希望看完的你有所收獲 :) thanks
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市搀崭,隨后出現(xiàn)的幾起案子叨粘,更是在濱河造成了極大的恐慌,老刑警劉巖瘤睹,帶你破解...
    沈念sama閱讀 210,914評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件升敲,死亡現(xiàn)場離奇詭異,居然都是意外死亡轰传,警方通過查閱死者的電腦和手機驴党,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,935評論 2 383
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來获茬,“玉大人港庄,你說我怎么就攤上這事∷∏” “怎么了鹏氧?”我有些...
    開封第一講書人閱讀 156,531評論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長佩谣。 經(jīng)常有香客問我把还,道長,這世上最難降的妖魔是什么茸俭? 我笑而不...
    開封第一講書人閱讀 56,309評論 1 282
  • 正文 為了忘掉前任笨篷,我火速辦了婚禮,結(jié)果婚禮上瓣履,老公的妹妹穿的比我還像新娘。我一直安慰自己练俐,他們只是感情好袖迎,可當(dāng)我...
    茶點故事閱讀 65,381評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著腺晾,像睡著了一般燕锥。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上悯蝉,一...
    開封第一講書人閱讀 49,730評論 1 289
  • 那天归形,我揣著相機與錄音,去河邊找鬼鼻由。 笑死暇榴,一個胖子當(dāng)著我的面吹牛厚棵,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播蔼紧,決...
    沈念sama閱讀 38,882評論 3 404
  • 文/蒼蘭香墨 我猛地睜開眼婆硬,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了奸例?” 一聲冷哼從身側(cè)響起彬犯,我...
    開封第一講書人閱讀 37,643評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎查吊,沒想到半個月后谐区,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,095評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡逻卖,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,448評論 2 325
  • 正文 我和宋清朗相戀三年宋列,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片箭阶。...
    茶點故事閱讀 38,566評論 1 339
  • 序言:一個原本活蹦亂跳的男人離奇死亡虚茶,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出仇参,到底是詐尸還是另有隱情嘹叫,我是刑警寧澤,帶...
    沈念sama閱讀 34,253評論 4 328
  • 正文 年R本政府宣布诈乒,位于F島的核電站罩扇,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏怕磨。R本人自食惡果不足惜喂饥,卻給世界環(huán)境...
    茶點故事閱讀 39,829評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望肠鲫。 院中可真熱鬧员帮,春花似錦、人聲如沸导饲。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,715評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽渣锦。三九已至硝岗,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間袋毙,已是汗流浹背型檀。 一陣腳步聲響...
    開封第一講書人閱讀 31,945評論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留听盖,地道東北人胀溺。 一個月前我還...
    沈念sama閱讀 46,248評論 2 360
  • 正文 我出身青樓裂七,卻偏偏與公主長得像,于是被迫代替她去往敵國和親月幌。 傳聞我的和親對象是個殘疾皇子碍讯,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,440評論 2 348

推薦閱讀更多精彩內(nèi)容