iOS 架构模式

MVC-面向对象

image

以上三者的交互关系。什么关系?

  1. Model 不与 View直接通话,如图中Model和View之间的两黄实线。
  2. Model 与 Controller 通话,如图中Model和Controller中两灰色虚实线、当中的绿色箭头、Model上橙色的KVO。
  3. View与 controller 通话,如图中Controller和View之间两灰色虚实线、当中的Outlet绿色箭头、黄色的delegate和data source。
  4. View上action 与 controller 上的target。
  5. Model上KVO发送端与controller上的黄色接受端。

MVC实际使用

目前App 中最常用的code习惯如下图

image

通过这张图可以发现, 用户信息页面作为业务场景Scene需要展示多种数据M(Blog/Draft/UserInfo), 所以对应的有多个View(blogTableView/draftTableView/image…), 但是, 每个MV之间并没有一个连接层C, 本来应该分散到各个C层处理的逻辑全部被打包丢到了Scene这一个地方处理, 也就是M-C-V变成了MM…-Scene-…VV, C层就这样莫名其妙的消失了.

另外, 作为V的两个cell直接耦合了M(blog/draft), 这意味着这两个V的输入被绑死到了相应的M上, 复用无从谈起.

MVC正常使用

那么正确的MVC是什么呢?如下图

image

MVC 的缺点

1、胖model的产生
2、Massive View Controller的产生
3、过度隔离V&M
4、产生太多轻量级的model
5、遗失网络逻辑
6、较差的可测试性
7、业务逻辑与视图逻辑强耦合

相关参考连接

https://www.jianshu.com/p/7e5fc5fb7ba3
https://www.cnblogs.com/AnnieBabygn/p/7872552.html

MVP-面向接口

image

Model View Presenter


5.png

Controller中的所有逻辑都放在Presenter中实现,与MVC不同的是Model与View是没有任何联系的,都是通过Presenter来交互

Presenter持有MVPView与MVPModel

#import "MVPViewController.h"
#import "Presenter.h"
#import "MVPModel.h"
#import "MVPView.h"
@interface MVPViewController () 
@property (nonatomic, strong) Presenter *presenter;
@property (nonatomic, strong) MVPView  *mvpView;
@property (nonatomic, strong) MVPModel *mvpModel;
@end
@implementation MVPViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    _presenter = [[Presenter alloc] init];
    _mvpView = [[MVPView alloc] init];
    _mvpView.frame = self.view.bounds;
    [self.view addSubview:_mvpView];
    _mvpModel = [MVPModel new];
    _mvpModel.content = @"MVP的模式";
    // model还没赋值
    _presenter.model = _mvpModel;
    _presenter.view = _mvpView;
    [_presenter usageLogic];
}
@end

MVVM-响应式编程

MVVM其实是MVC的升级版,controller & view 直接通过viewModel 读取数据然后展示在界面上

MVVM概念

7.png

MVVM 简单一点说 : 双向绑定(通过viewModel 绑定view 与 model)

使用的严格限制

1、View 引用了viewModel ,但是反过来不行
2、viewModel引用了model,但是反过来不行
3、MVVM模式依赖于数据绑定,它是一个框架级别的特性,用于自动连接对象属性和UI控件。

viewModel 主要通过以下两种方式通知View更新UI

1、Block
2、使用reactiveCocoa库

这个库包含了函数式编程和响应式编程。其实reactiveCocoa库就是MVVM模式的核心。
不使用 RAC :ViewModel处理完数据需要刷新 View等操作都是通过 Block回调来实现,不免是有些麻烦的。
使用 RAC :在 View初始化的时候就和 ViewModel进行绑定,只要 ViewModel的数据有所变化,便自动更新 View。
RAC 缺点:数据绑定使得一个位置的 Bug被快速传递到别的位置,要定位原始出问题的地方就变得不那么容易了

ReactiveCocoa

reactiveCocoa 俗称RAC,属于函数式响应编程,极大的简化了逻辑,方便使用

1、替换代理方法
2、替换KVO
3、替换NSNotification
4、替换UIControl 的一些响应事件
5、替换NSTimer
等等,采用管道式通信机制,使逻辑更易理解

ReactiveCocoa入门教程:第一部分
ReactiveCocoa入门教程: 第二部分
ReactiveCocoa源码解析
ReactiveCocoa常用方法
MVVM+RAC 从框架到实战

RAC使用

使用RAC模拟请求客户档案与仓库档案

1.先请求客户档案数量,再根据数量分批次请求客户档案数据

2.先请求仓库档案数量,再根据数量分批次请求仓库档案数据

- (void)viewDidLoad

  RACSignal *consumerSignal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {    

        //模拟发送一次获取客户更新数量的请求
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{

            //假如获取到count 5
            [self requestConsumerDataWith:subscriber];
        });

        return nil;

    }];

    [consumerSignal subscribeNext:^(id  _Nullable x) {

g
       NSLog(@"客户档案更新结束%@",x);
    }];

    RACSignal *warehouseSignal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {

        //模拟发送一次获取仓库更新数量的请求
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{

            //假如获取到count 5
            [self requestConsumerDataWith:subscriber];
        });

        return nil;

    }];

    [warehouseSignal subscribeNext:^(id  _Nullable x) {

        NSLog(@"仓库档案更新结束%@",x);
    }];

    //连接两个信号,只有两个信号都触发时,才能刷新UI 或者让HUD 消失
    [self rac_liftSelector:@selector(updateUIWithR1:r3:) withSignalsFromArray:@[warehouseSignal,consumerSignal]];  

}

- (void)requestConsumerDataWith:(id<RACSubscriber>)subScriber_consumer{

    RACSignal *consumerSignal = nil;

    for (int i = 1; i < 5; i++) {

        RACSignal *single_temp = [[RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {

            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{

                [subscriber sendNext:@(i)];

            });

            return nil;

        }]delay:i];

        if (!consumerSignal) {
            consumerSignal = single_temp;
        }else{
            consumerSignal = [consumerSignal combineLatestWith:single_temp];
        }
    }

    [consumerSignal subscribeNext:^(id  _Nullable x) {
        [subScriber_consumer sendNext:@"客户档案请求成功!!!"];
    }];
}

- (void)requestWarehouseDataWith:(id<RACSubscriber>)subScriber_warehouse{

    RACSignal *consumerSignal = nil;

    for (int i = 1; i < 5; i++) {

        RACSignal *single_temp = [[RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {

            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{

                [subscriber sendNext:@(i)];

            });

            return nil;

        }]delay:i];

        if (!consumerSignal) {

            consumerSignal = single_temp;

        }else{

            consumerSignal = [consumerSignal combineLatestWith:single_temp];

        }
    }

    [consumerSignal subscribeNext:^(id  _Nullable x) {
          [subScriber_warehouse sendNext:@"仓库档案请求成功!!!"];
    }];
}

// 更新UI

- (void)updateUIWithR1:(id)data r3:(id)data2{
  
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350

推荐阅读更多精彩内容