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  _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  _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)subScriber_consumer{

    RACSignal *consumerSignal = nil;

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

        RACSignal *single_temp = [[RACSignal createSignal:^RACDisposable * _Nullable(id  _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)subScriber_warehouse{

    RACSignal *consumerSignal = nil;

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

        RACSignal *single_temp = [[RACSignal createSignal:^RACDisposable * _Nullable(id  _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{
  

你可能感兴趣的:(iOS 架构模式)