iOS 底层面试

iOS 面试锦囊之架构设计MVC、MVVM、MVP

2021-04-12  本文已影响0人  flowerflower
💪💪

一个好的架构应有的特点

如何解耦???
解决复杂性的最简单的方式就是多个实体间按照单一责任原则拆分职责。

优点:对Controller进行搜身,将View的内部的细节封装起来了,外接不知道View的内部具体实现
缺点:View依赖于Model,View绑定了模型

废话不得说,我们一起来看个简单的小demo. 简单的一个列表展示,分别用三种形式展现:


列表数据展示

从图中我们可以看到一个列表的展示,对几乎刚入门的开发者来说都是so easy,但是我们这里研究是架构模式,是一种思想。
Demo:

//ViewController继承自UITableViewController
#import "ViewController.h"
#import "HTTPRequest.h"
#import "MJExtension/MJExtension.h"
#import "NewsModel.h"
#import "NewsCell.h"
#define  Success [resposeObject[@"status"] isEqualToString:@"000000"]
@interface ViewController ()
@property(nonatomic,strong)NSMutableArray <NewsModel *>*dataArr;

@end
@implementation ViewController

#pragma mark - viewDidLoad
- (void)viewDidLoad {
    [super viewDidLoad];
    [self loadDataFormNetwork];
}

#pragma mark - loadDataFormNetwork
- (void)loadDataFormNetwork{
    __weak typeof(self) weakSelf = self;
    [HTTPRequest GET:@"http://www.mocky.io/v2/5deb73662f0000690007e246" parameters:nil success:^(id  _Nonnull resposeObject) {
        
        if (Success) {
            weakSelf.dataArr = [NewsModel mj_objectArrayWithKeyValuesArray:resposeObject[@"data"]];
            [weakSelf.tableView reloadData];
        }
    } failure:^(NSError * _Nonnull error) {  }];
}

pragma mark - <UITableViewDataSource,UITableViewDelegate>
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
    return self.dataArr.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
    NewsCell *cell = [tableView dequeueReusableCellWithIdentifier:@"NewsCellID" forIndexPath:indexPath];
    cell.model= [self.dataArr objectAtIndex:indexPath.row];
    return cell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
    return [self.dataArr objectAtIndex:indexPath.row].cellHeight;
}
#pragma mark - setter && getter Method
- (NSMutableArray *)dataArr{
    if (!_dataArr) {
        _dataArr = [NSMutableArray array];
    }
    return _dataArr;
}
@end

Controller说明:从控制器导入的头文件中我们可以发现,控制器持有Model以及View,同时由控制器层发送网络请求,请求到数据之后将数据保存在Model中,控制器相当于Model与View的中介者。

/****************Model.h*********************/
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface NewsModel : NSObject

@property(nonatomic, copy)NSString *title;
@property(nonatomic, copy)NSString *content;
@property(nonatomic, assign)CGFloat cellHeight;
@end
NS_ASSUME_NONNULL_END

/****************Model.m*********************/
#import "NewsModel.h"
@implementation NewsModel
- (CGFloat)cellHeight{
    
    if(_cellHeight == 0){
        CGFloat titleHeight  = 40;
        CGFloat bottomSpac = 10;
        NSMutableDictionary *attrs = [NSMutableDictionary dictionary];
        attrs[NSFontAttributeName] = [UIFont systemFontOfSize:15];
        CGSize maxSize = CGSizeMake([UIScreen mainScreen].bounds.size.width - 2 * 12, MAXFLOAT);
        CGSize sizeToFit =    [self.content boundingRectWithSize:maxSize options:NSStringDrawingUsesLineFragmentOrigin attributes:attrs context:nil].size;
        _cellHeight += sizeToFit.height + titleHeight + bottomSpac;
    }
    return _cellHeight;
}
@end

Model说明:存放数据,并将cellHeight的高度进行保存,因为请求之后我们将数据保存到了模型中,从而我们知道模型中有哪些数据,从而对高度进行提前缓存。

/****************NewsCell.h*********************/
#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN
@class NewsModel;
@interface NewsCell : UITableViewCell
@property(nonatomic,strong)NewsModel *model;
@end

NS_ASSUME_NONNULL_END

/****************NewsCell.m*********************/
#import "NewsModel.h"
@implementation NewsCell
- (void)setModel:(NewsModel *)model{
    _model = model;
    self.textLabel.text  = model.title;
    self.detailTextLabel.text = model.content;
}
@end

View说明:简称UI层,负责显示数据,当View层状态发生改变时,会反击给控制器。


文字解读:
控制器用了Presenter,Presenter去处理UI以及业务逻辑,相当于取代了控制器的角色,从而又对控制器再次搜身,


MVVM

图片.png

共同点:跟MVP雷同,View和Model的很多逻辑都交给了VieModel处理
不同点:属性监听和绑定的问题,View可以监听ViewModel里面数据的改变,一旦发生改变,View的数据会自动更新(配合RAC更强大),不过笔记认为RAC这个框架体积过大,笔者觉得没必要用。
核心:View和ViewModel是双向绑定的,ViewModel可以负责创建拥有这个View,View又可以拥有这个ViewModel

MVC、MVVM、MVP就论绪到这里!!!
经过上面的讲解,相信你对Contoller的臃肿问题已经有了一些自己的见解。


对Controller 的臃肿问题,首先我们要先思考 什么样的内容才应该放到 Controller 中?,在我看来Controller 里面就只应该存放这些不能复用的代码

题外话
面试官打开自己的App,然后问你如果是你,你会怎么架构?

可以这样解答


图片.png

业务层也就是服务层
我个人对于逻辑的抽取,有以下总结。
可以将网络请求抽象到单独的类中
把网络请求封装成对象其实是使用了设计模式中的 Command 模式,它有以下好处:


总结

不要纠结于使用MVC、MVP还是MVVM,也不要为了装的显得逼格高一点而大材小用(eg:笔者讲的🌰,不过最主要在于是思想)。之所以会产生一些新的架构模式,是因为有些大型项目的业务逻辑越来越复杂,从而才会繁衍出新的花样,当然找到合适的才是最主要的!

上一篇下一篇

猜你喜欢

热点阅读