美文网首页
iOS中的架构及设计模式

iOS中的架构及设计模式

作者: 文子飞_ | 来源:发表于2020-12-21 17:21 被阅读0次

iOS中的三层架构、四层架构

三层架构
  • 界面层 (MVC、MVP、MVVM)
  • 业务层
  • 数据层(网络数据&本地数据)
四层架构
  • 界面层 (MVC、MVP、MVVM)
  • 业务层
  • 网络层
  • 本地数据层

其中,界面层的架构模式又分为好多种,从最开始的MVC模式,演化到MVP,然后到现在的MVVM模式,在不断的演化过程中核心思想归根结底还是:降低各组件之间的耦合度,使得数据的流向更加清晰明了。


image.png
App目录结构
  • CommonObject
    • Class
      • AppDelegate
      • AppPages
        • Login
        • Home
          • Server
          • ViewModel
          • Model
          • View
          • ViewController
        • Me
      • Protocol
      • Base
      • Define
      • CustomUI
      • Category
      • Manager
      • Utils
        + Data
        + Http
一、MVC(Model、View、Controller

MVC是比较直观的架构模式,最核心的就是通过Controller层来进行调控。

  • Model和View永远不能相互通信,只能通过Controller传递。
  • Controller可以直接与Model对话(读写调用Model),Model通过NOtification和KVO机制与Controller间接通信。
  • Controller可以直接与View对话,View通过action向Controller报告事件的发生(用户点击了按钮)。Controller是View的直接数据源
    优缺点
  • 优点:对于混乱的项目组织方式,有了一个明确的组织方式。通过Controller来掌控全局,同时将View展示和Model的变化分开
  • 缺点:愈发笨重的Controller,随着业务逻辑的增加,大量的代码放进Controller,导致Controller越来越臃肿,堆积成千上万行代码,后期维护起来费时费力。


    image.png
MVC变种

优缺点:

  • 优点:对Controller进行瘦身,将View内部的细节封装起来了,外界不知道View内部的具体实现
  • 缺点:View依赖于Model



二、MVP(Model、View、Presenter)

我理解的MVP设计模式,是在MVC的基础上对Controller进行瘦身。Controller只是用来管理Presenter,然后由Presenter来负责Model和View之间的通信,以及View向Controller报告事件。

简单的示例代码如下

  • Presenter类
// Presenter.h
#import <UIKit/UIKit.h>

@interface Presenter : NSObject
- (instancetype)initWithController:(UIViewController *)controller;
@end


// Presenter.m
#import "Presenter.h"
#import "App.h"
#import "AppView.h"

@interface Presenter() <AppViewDelegate>
@property (weak, nonatomic) UIViewController   *controller;
@end

@implementation Presenter

- (instancetype)initWithController:(UIViewController *)controller
{
    if (self = [super init]) {
        self.controller = controller;
      
        // 创建View
        AppView *appView = [[AppView alloc] init];
        appView.frame = CGRectMake(100, 100, 100, 150);
        appView.delegate = self;
        [controller.view addSubview:appView];
      
        // 加载模型数据
        App *app = [[App alloc] init];
        app.name = @"QQ";
        app.image = @"QQ";
      
        // 赋值数据
        appView.iconView.image = [UIImage imageNamed:app.image];
        appView.nameLabel.text = app.name;
    }
    return self;
}

#pragma mark - AppViewDelegate
- (void)appViewDidClick:(AppView *)appView
{
    NSLog(@"presenter 监听了 appView 的点击");
}

@end
  • ViewController类
 // ViewController.m
 #import "ViewController.h"
 #import "Presenter.h"

 @interface ViewController ()
 @property (strong, nonatomic) Presenter *presenter;
 //@property (strong, nonatomic) OtherPresenter *presenter1;
 @end

 @implementation ViewController

 - (void)viewDidLoad {
     [super viewDidLoad];
  
     self.presenter = [[Presenter alloc] initWithController:self];
 }

 @end
三、MVVM(Model、View、ViewModel)

MVVM也是对Controller进行瘦身的一种策略,将业务逻辑放到ViewModel中去处理,比如发送网络请求,加载网络数据进行字典转模型操作等等。


image.png

简单的示例代码如下

  • HomeVC类:负责创建和显示视图
// HomeVC.m
@interface HomeVC ()
@property (nonatomic, strong) UITableView *homeTableView;
@property (nonatomic, strong) HomeVM *homeVM;
@end

@implementation HomeVC

#pragma mark - <Life Cycle>
- (void)viewDidLoad {
    [super viewDidLoad];
    
    // RAC网络请求
    @weakify(self);
    [[self.homeVM.homeCommand execute:nil] subscribeNext:^(id  _Nullable x) {
        @strongify(self);
        NSLog(@"currentThread = %@", [NSThread currentThread]);
        //NSLog(@"x = %@", x);
        [self.homeTableView reloadData];
    }];
    
    // ViewModel数据绑定到view上
    [self.homeVM bindVMWithView:self.homeTableView];
    
    // 订阅按钮事件
    [self.homeVM.cellButtonEventSignal subscribeNext:^(UIButton *x) {
        NSLog(@"x = %@", [x titleForState:UIControlStateNormal]);
    }];
    
}

- (void)dealloc {
    NSLog(@"%s", __func__);
}

#pragma mark - <Override>
- (void)createSubViews {
    [super createSubViews];
    [self.view addSubview:self.homeTableView];
}

- (void)addConstraints {
    [super addConstraints];
    [self.homeTableView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.mas_equalTo(self.view.mas_safeAreaLayoutGuideTop);
        make.left.right.bottom.mas_equalTo(self.view);
    }];
}

#pragma mark - <getter/setter>
- (HomeVM *)homeVM {
    if (_homeVM == nil) {
        _homeVM = [[HomeVM alloc] init];
    }
    return _homeVM;
}

- (UITableView *)homeTableView {
    if (_homeTableView == nil) {
        _homeTableView = [[UITableView alloc] init];
        _homeTableView.rowHeight = 120;
        _homeTableView.tableFooterView = [[UIView alloc] init];
    }
    return _homeTableView;
}

@end
  • HomeVM类:负责homeTableView的显示和业务逻辑处理
// HomeVM.h
@interface HomeVM : NSObject<ViewModelProtocol> {
    RACCommand *_homeCommand;
}

/// 网络请求RACCommand
@property (nonatomic, strong, readonly) RACCommand *homeCommand;
/// 按钮点击信号
@property (nonatomic, strong, readonly) RACReplaySubject *cellButtonEventSignal;

@end


// HomeVM.m
static NSString *HomeTableCellID = @"HomeTableCellID";

@interface HomeVM ()<UITableViewDataSource, UITableViewDelegate>

@property (nonatomic, copy) NSArray *homeCellVMs;
@property (nonatomic, strong) HomeTableCellVM *cellVM;

@end

@implementation HomeVM {
    RACReplaySubject *_cellButtonEventSignal;
}

- (RACCommand *)homeCommand {
    if (_homeCommand == nil) {
        _homeCommand = [[RACCommand alloc] initWithSignalBlock:^RACSignal * _Nonnull(id  _Nullable input) {
            // RACCommand的block
            return [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
                // RACSignal的block
                
                NSString *homeURL = [XMGNetworkManager urlWithHome];
                NSDictionary *homeParameters = [XMGNetworkManager paramWithHome];
                
                [XMGHttpManager POST:homeURL parameters:homeParameters progress:nil success:^(NSURLSessionDataTask *task, id responseObject) {
                    NSLog(@"responseObject = %@", responseObject);
                    int code = [[responseObject objectForKey:@"code"] intValue];
                    if (code == 0) {
                        // 推荐列表
                        NSDictionary *recommends = [[responseObject objectForKey:@"result"] objectForKey:@"recommends"];
                        NSArray *courses = [recommends objectForKey:@"courses"];
                        courses = [[courses.rac_sequence map:^id _Nullable(id  _Nullable value) {
                            HomeModel *model = [HomeModel yy_modelWithJSON:value];
                            HomeTableCellVM *cellVM = [[HomeTableCellVM alloc] init];
                            cellVM.model = model;
                            return cellVM;
                        }] array];
                        // dic->model完成
                        self.homeCellVMs = courses;
                        [subscriber sendNext:courses];
                        [subscriber sendCompleted];
                    }
                } failure:^(NSURLSessionDataTask *task, NSError *error) {
                    [subscriber sendError:error];
                }];
                
                
                /*
                [LFNetManager requestWithAFURL:homeURL httpMethod:Request_Type_POST params:homeParameters success:^(id result, int code) {
                    
                    if (code == 0) {
                        // 推荐列表
                        NSDictionary *recommends = [[result objectForKey:@"result"] objectForKey:@"recommends"];
                        NSArray *courses = [recommends objectForKey:@"courses"];
                        courses = [[courses.rac_sequence map:^id _Nullable(id  _Nullable value) {
                            HomeModel *model = [HomeModel yy_modelWithJSON:value];
                            return model;
                        }] array];
                        // dic->model完成
                        [subscriber sendNext:courses];
                        [subscriber sendCompleted];
                    }
                    
                } failure:^(NSError *err) {
                    [subscriber sendError:err];
                }];
                */
                
//                [HomeServer loadHomeList:homeParameters success:^(id  _Nonnull response, int code) {
//                    
//                } failure:^(NSError * _Nonnull error) {
//                    
//                }];
                
                return nil;
            }];
        }];
    }
    return _homeCommand;
}

#pragma mark - <ViewModelProtocol>
- (void)bindVMWithView:(UIView *)view {
    UITableView *tableView = (UITableView *)view;
    tableView.dataSource = self;
    tableView.delegate = self;
    
    [tableView registerClass:[HomeTableCell class] forCellReuseIdentifier:HomeTableCellID];
}

#pragma mark - <UITableViewDataSource/UITableViewDelegate>
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return self.homeCellVMs.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    HomeTableCell *cell = [tableView dequeueReusableCellWithIdentifier:HomeTableCellID forIndexPath:indexPath];
    HomeTableCellVM *cellVM = self.homeCellVMs[indexPath.row];
    [cellVM bindVMWithView:cell];
    [cell.button addTarget:self action:@selector(cellButtonAction:) forControlEvents:UIControlEventTouchUpInside];
    return cell;
}

#pragma mark - <Event>
- (void)cellButtonAction:(UIButton *)sender {
    [self.cellButtonEventSignal sendNext:sender];
    //[self.cellButtonEventSignal sendCompleted];
}

#pragma mark - <getter/setter>
- (RACReplaySubject *)cellButtonEventSignal {
    if (_cellButtonEventSignal == nil) {
        _cellButtonEventSignal = [RACReplaySubject subject];
    }
    return _cellButtonEventSignal;
}

@end
  • HomeTableCellVM类:负责Cell的显示和业务逻辑处理
// HomeTableCellVM.h
@interface HomeTableCellVM : NSObject<ViewModelProtocol>
@property (nonatomic, strong) HomeModel *model;
@end

// HomeTableCellVM.m
@implementation HomeTableCellVM

#pragma mark - <ViewModelProtocol>
- (void)bindVMWithView:(UIView *)view {
    HomeTableCell *cell = (HomeTableCell *)view;
    
    [cell.imgView sd_setImageWithURL:[NSURL URLWithString:self.model.courseImage]];
    cell.titleLabel.text = self.model.courseName;
    cell.subTitleLabel.text = self.model.grade;
    [cell.button setTitle:self.model.grade forState:UIControlStateNormal];
}

@end

四、三层架构
  • HomeServer类:处理Home业务层 获取本地、网络列表
// HomeServer.h
@interface HomeServer : NSObject

+ (void)loadHomeList:(NSDictionary *)parameters
             success:(void(^)(id response, int code))successBlock
             failure:(void(^)(NSError *error))failureBlock;

@end


// HomeServer.m
#import "AppDBTool.h"
#import "LFNetManager.h"

@interface HomeServer ()

@property (nonatomic, strong) AppDBTool *appDB;
@property (nonatomic, strong) LFNetManager *appHttp;

@end

@implementation HomeServer

- (instancetype)init
{
    self = [super init];
    if (self) {
        self.appDB = [AppDBTool new];
        self.appHttp = [LFNetManager new];
    }
    return self;
}

+ (void)loadHomeList:(NSDictionary *)parameters
             success:(void(^)(id response, int code))successBlock
             failure:(void(^)(NSError *error))failureBlock {
    // 获取本地数据
    [AppDBTool loadLocalHomeList:@{} success:^(NSArray * _Nonnull lists) {
        if (lists.count) {
            successBlock(lists, 200);
        } else {
            // 获取网络数据
            [LFNetManager requestWithAFURL:@"homeURL" httpMethod:Request_Type_GET params:parameters success:^(id result, int code) {
                successBlock(result, code);
            } failure:^(NSError *err) {
                failureBlock(err);
            }];
        }
    } failure:^(NSError * _Nonnull error) {
        // 获取网络数据
        [LFNetManager requestWithAFURL:@"homeURL" httpMethod:Request_Type_GET params:parameters success:^(id result, int code) {
            successBlock(result, code);
        } failure:^(NSError *err) {
            failureBlock(err);
        }];
    }];
}

@end

相关文章

  • iOS MVVM架构总结

    参考:iOS 中MVC设计模式iOS MVVM架构iOS MVVM-框架介绍iOS 架构模式MVVM的实践总结iO...

  • iOS组件化及架构设计

    iOS组件化及架构设计 iOS组件化及架构设计

  • iOS中的架构及设计模式

    iOS中的三层架构、四层架构 三层架构 界面层 (MVC、MVP、MVVM) 业务层 数据层(网络数据&本地数据)...

  • iOS 架构模式学习笔记

    iOS 架构模式学习笔记 设计模式 设计模式 和 编码技巧 、架构模式的区别: 设计模式:特定场景下的最佳实践 如...

  • iOS开发小帖:设计模式

    设计模式精彩文章 iOS 架构模式--解密 MVC,MVP,MVVM以及VIPER架构 MVP设计模式 基于面向协...

  • iOS求职面试题目搜集<阿里,腾讯,网易>

    iOS系统原理: 第三方: 性能、内存优化: 设计模式: 系统架构设计: 网络模型协议数据: 动画原理及使用: 数...

  • 设计模式概览

    iOS MVC中的设计模式 MVC是一种用户界面架构模式,同样的MVVM、MVP等都是MVC的变种,iOS平台中用...

  • 基于工作空间框架实现的iOS分层架构实现

    iOS分层架构简介 在软件工程中,设计模式(design pattern)是对软件设计中普遍存在(反复出现)的各种...

  • 架构学习

    参考:http://ios.jobbole.com/84897/架构模式 简述猿题库架构设计 "没有最好的架构,只...

  • iOS 设计模式

    MVC和MVVM?它是iOS开发中阻力最低的架构模式。MVC代码量最小,设计开销最小的模式。MVC常见的问题: 在...

网友评论

      本文标题:iOS中的架构及设计模式

      本文链接:https://www.haomeiwen.com/subject/bcornktx.html